diff options
Diffstat (limited to 'src/main')
15 files changed, 431 insertions, 16 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 42c4d70a0..2ab83b512 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -9,6 +9,7 @@ import at.hannibal2.skyhanni.config.SackData import at.hannibal2.skyhanni.config.commands.Commands.init import at.hannibal2.skyhanni.data.ActionBarStatsData import at.hannibal2.skyhanni.data.BlockData +import at.hannibal2.skyhanni.data.BossbarData import at.hannibal2.skyhanni.data.ChatManager import at.hannibal2.skyhanni.data.CropAccessoryData import at.hannibal2.skyhanni.data.EntityData @@ -228,6 +229,7 @@ import at.hannibal2.skyhanni.features.mining.DeepCavernsParkour import at.hannibal2.skyhanni.features.mining.HighlightMiningCommissionMobs import at.hannibal2.skyhanni.features.mining.KingTalismanHelper import at.hannibal2.skyhanni.features.mining.crystalhollows.CrystalHollowsNamesInCore +import at.hannibal2.skyhanni.features.mining.eventtracker.MiningEventTracker import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker import at.hannibal2.skyhanni.features.minion.MinionCollectLogic import at.hannibal2.skyhanni.features.minion.MinionFeatures @@ -443,6 +445,7 @@ class SkyHanniMod { loadModule(TrackerManager) loadModule(UtilsPatterns) loadModule(PetAPI) + loadModule(BossbarData) // APIs loadModule(BazaarApi()) @@ -725,6 +728,7 @@ class SkyHanniMod { loadModule(SprayDisplay()) loadModule(HighlightPlaceableNpcs()) loadModule(PresentWaypoints()) + loadModule(MiningEventTracker()) loadModule(JyrreTimer()) loadModule(NewYearCakeReminder()) loadModule(SulphurSkitterBox()) 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 a2820fbfc..69b096b31 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -55,6 +55,7 @@ import at.hannibal2.skyhanni.test.SkyHanniConfigSearchResetCommand import at.hannibal2.skyhanni.test.SkyHanniDebugsAndTests import at.hannibal2.skyhanni.test.TestBingo import at.hannibal2.skyhanni.test.WorldEdit +import at.hannibal2.skyhanni.test.command.CopyBossbarCommand import at.hannibal2.skyhanni.test.command.CopyItemCommand import at.hannibal2.skyhanni.test.command.CopyNearbyEntitiesCommand import at.hannibal2.skyhanni.test.command.CopyNearbyParticlesCommand @@ -356,6 +357,10 @@ object Commands { "Copies the scoreboard data to the clipboard" ) { CopyScoreboardCommand.command(it) } registerCommand( + "shcopybossbar", + "Copies the name of the bossbar to the clipboard, including formatting codes" + ) { CopyBossbarCommand.command(it) } + registerCommand( "shcopyitem", "Copies information about the item in hand to the clipboard" ) { CopyItemCommand.command() } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java index 462908f6e..9b385494b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java @@ -3,12 +3,17 @@ package at.hannibal2.skyhanni.config.features.mining; import at.hannibal2.skyhanni.config.FeatureToggle; import com.google.gson.annotations.Expose; import io.github.moulberry.moulconfig.annotations.Accordion; +import io.github.moulberry.moulconfig.annotations.Category; import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; import io.github.moulberry.moulconfig.annotations.ConfigOption; public class MiningConfig { @Expose + @Category(name = "Mining Event Tracker", desc = "Settings for the Mining Event Tracker") + public MiningEventConfig miningEvent = new MiningEventConfig(); + + @Expose @ConfigOption(name = "Powder Tracker", desc = "") @Accordion public PowderTrackerConfig powderTracker = new PowderTrackerConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningEventConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningEventConfig.java new file mode 100644 index 000000000..261283c7b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningEventConfig.java @@ -0,0 +1,61 @@ +package at.hannibal2.skyhanni.config.features.mining; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +public class MiningEventConfig { + +// @Expose +// @ConfigOption(name = "Enabled", desc = "Show information about upcoming Dwarven Mines and Crystal Hollows mining events, also enables you sending data.") +// @ConfigEditorBoolean +// @FeatureToggle +// public boolean enabled = true; +// +// @Expose +// @ConfigOption(name = "Show Outside Mining Islands", desc = "Shows the event tracker when you are not inside of the Dwarven Mines or Crystal Hollows.") +// @ConfigEditorBoolean +// public boolean outsideMining = true; +// +// @Expose +// @ConfigOption(name = "What to Show", desc = "Choose which island's events are shown in the gui.") +// @ConfigEditorDropdown +// public ShowType showType = ShowType.BOTH; +// +// @Expose +// @ConfigOption(name = "Show Warnings For Events", desc = "Shows the warnings when select mining events are about to start.") +// @ConfigEditorBoolean +// @FeatureToggle +// public boolean showWarnings = false; + + //todo remove when released + @Expose + @ConfigOption(name = "Send Test data", desc = "Sends test data to make sure the api works.") + @ConfigEditorBoolean + @FeatureToggle + public boolean sendData = true; + +// @Expose +// @ConfigOption(name = "Events to Warn for", desc = "Choose which mining events you get warned about.") +// @ConfigEditorDraggableList +// public List<MiningEvent> eventsToWarn = new ArrayList<>(Collections.singletonList(MiningEvent.DOUBLE_POWDER)); + + public enum ShowType { + BOTH("Both Mining Islands"), + CRYSTAL("Crystal Hollows Only"), + DWARVEN("Dwarven Mines Only") + ; + + private final String str; + + ShowType(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/BossbarData.kt b/src/main/java/at/hannibal2/skyhanni/data/BossbarData.kt new file mode 100644 index 000000000..75ad8df9b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/BossbarData.kt @@ -0,0 +1,33 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.events.BossbarUpdateEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import net.minecraft.entity.boss.BossStatus +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object BossbarData { + private var bossbar: String? = null + private var previousServerBossbar = "" + + fun getBossbar() = bossbar ?: "" + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + val oldBossbar = bossbar ?: return + previousServerBossbar = oldBossbar + bossbar = null + } + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + val bossbarLine = BossStatus.bossName ?: return + if (bossbarLine.isBlank() || bossbarLine.isEmpty()) return + if (bossbarLine == bossbar) return + if (bossbarLine == previousServerBossbar) return + if (previousServerBossbar.isNotEmpty()) previousServerBossbar = "" + + bossbar = bossbarLine + BossbarUpdateEvent(bossbarLine).postAndCatch() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index 78017b7bc..3f6ec7051 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -26,20 +26,40 @@ import net.minecraftforge.fml.common.network.FMLNetworkEvent import kotlin.concurrent.thread class HypixelData { - private val group = RepoPattern.group("data.hypixeldata") - private val tabListProfilePattern by group.pattern("tablistprofile", "§e§lProfile: §r§a(?<profile>.*)") - private val lobbyTypePattern by group.pattern("lobbytype", "(?<lobbyType>.*lobby)\\d+") - private val islandNamePattern by group.pattern("islandname", "(?:§.)*(Area|Dungeon): (?:§.)*(?<island>.*)") + private val patternGroup = RepoPattern.group("data.hypixeldata") + private val tabListProfilePattern by patternGroup.pattern( + "tablistprofile", + "§e§lProfile: §r§a(?<profile>.*)" + ) + private val lobbyTypePattern by patternGroup.pattern( + "lobbytype", + "(?<lobbyType>.*lobby)\\d+" + ) + private val islandNamePattern by patternGroup.pattern( + "islandname", + "(?:§.)*(Area|Dungeon): (?:§.)*(?<island>.*)" + ) private var lastLocRaw = 0L companion object { + private val patternGroup = RepoPattern.group("data.hypixeldata") + private val serverIdScoreboardPattern by patternGroup.pattern( + "serverid.scoreboard", + "§7\\d+/\\d+/\\d+ §8(?<servertype>[mM])(?<serverid>\\S+)" + ) + private val serverIdTablistPattern by patternGroup.pattern( + "serverid.tablist", + " Server: §r§8(?<serverid>\\S+)" + ) + var hypixelLive = false var hypixelAlpha = false var inLobby = false var inLimbo = false var skyBlock = false var skyBlockIsland = IslandType.UNKNOWN + var serverId: String? = null //Ironman, Stranded and Bingo var noTrade = false @@ -70,6 +90,24 @@ class HypixelData { val lobbyType get() = locraw["lobbytype"] ?: "" val mode get() = locraw["mode"] ?: "" val map get() = locraw["map"] ?: "" + + fun getCurrentServerId(): String? { + if (!LorenzUtils.inSkyBlock) return null + if (serverId != null) return serverId + + ScoreboardData.sidebarLinesFormatted.forEach { serverIdScoreboardPattern.matchMatcher(it) { + val serverType = if (group("servertype") == "M") "mega" else "mini" + serverId = "$serverType${group("serverid")}" + return serverId + } } + + TabListData.getTabList().forEach { serverIdTablistPattern.matchMatcher(it) { + serverId = group("serverid") + return serverId + } } + + return serverId + } } private var loggerIslandChange = LorenzLogger("debug/island_change") @@ -82,6 +120,7 @@ class HypixelData { inLobby = false locraw.forEach { locraw[it.key] = "" } joinedWorld = System.currentTimeMillis() + serverId = null } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/events/BossbarUpdateEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/BossbarUpdateEvent.kt new file mode 100644 index 000000000..7dd0d10bb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/BossbarUpdateEvent.kt @@ -0,0 +1,3 @@ +package at.hannibal2.skyhanni.events + +class BossbarUpdateEvent(val bossbar: String) : LorenzEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEvent.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEvent.kt new file mode 100644 index 000000000..f5d8e26d8 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEvent.kt @@ -0,0 +1,26 @@ +package at.hannibal2.skyhanni.features.mining.eventtracker + +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds + +enum class MiningEvent(val eventName: String, val defaultLength: Duration, private val colourCode: Char) { + GONE_WITH_THE_WIND("GONE WITH THE WIND", 18.minutes, '9'), + DOUBLE_POWDER("2X POWDER", 15.minutes, 'b'), + GOBLIN_RAID("GOBLIN RAID", 5.minutes, 'c'), + BETTER_TOGETHER("BETTER TOGETHER", 18.minutes, 'd'), + RAFFLE("RAFFLE", 160.seconds, '6'), + MITHRIL_GOURMAND("MITHRIL GOURMAND", 10.minutes, 'b'), + ; + + override fun toString(): String { + return "§$colourCode$eventName" + } + + companion object { + fun fromBossbarName(bossbarName: String): MiningEvent? { + return MiningEvent.entries.find { it.eventName == bossbarName.removeColor() } + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventData.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventData.kt new file mode 100644 index 000000000..ee2033ed4 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventData.kt @@ -0,0 +1,13 @@ +package at.hannibal2.skyhanni.features.mining.eventtracker + +import at.hannibal2.skyhanni.data.IslandType +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +data class MiningEventData( + @Expose @SerializedName("server_type") val serverType: IslandType, + @Expose @SerializedName("server_id") val serverId: String, + @Expose val event: MiningEvent, + @Expose @SerializedName("time_left") val timeRemaining: Long, + @Expose @SerializedName("reporter_uuid") val uuid: String +) diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt new file mode 100644 index 000000000..1fef5b2ee --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt @@ -0,0 +1,156 @@ +package at.hannibal2.skyhanni.features.mining.eventtracker + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigManager +import at.hannibal2.skyhanni.data.BossbarData +import at.hannibal2.skyhanni.data.HypixelData +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.ScoreboardData +import at.hannibal2.skyhanni.events.BossbarUpdateEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.TabListData +import at.hannibal2.skyhanni.utils.TimeUtils +import at.hannibal2.skyhanni.utils.getBoolean +import at.hannibal2.skyhanni.utils.getStringOrValue +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import kotlinx.coroutines.launch +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.seconds + +class MiningEventTracker { + private val config get() = SkyHanniMod.feature.mining.miningEvent + + private val patternGroup = RepoPattern.group("mining.eventtracker") + private val bossbarPassivePattern by patternGroup.pattern( + "bossbar.passive", + "§e§lPASSIVE EVENT (?<event>.+) §e§lRUNNING FOR §a§l(?<time>\\S+)§r" + ) + private val bossbarActivePattern by patternGroup.pattern( + "bossbar.active", + "§e§lEVENT (?<event>.+) §e§lACTIVE IN (?<area>.+) §e§lfor §a§l(?<time>\\S+)§r" + ) + private val eventStartedPattern by patternGroup.pattern( + "started", + "(?:§.)*\\s+(?:§.)+§l(?<event>.+) STARTED!" + ) + private val eventEndedPattern by patternGroup.pattern( + "ended", + "(?:§.)*\\s+(?:§.)+§l(?<event>.+) ENDED!" + ) + + private var lastRequestSent = SimpleTimeMark.farPast() + private var lastWorldSwitch = SimpleTimeMark.farPast() + private var eventEndTime = SimpleTimeMark.farPast() + + private var lastSentEvent: MiningEvent? = null + + @SubscribeEvent + fun onWorldChange(event: LorenzWorldChangeEvent) { + lastRequestSent = SimpleTimeMark.now() + lastWorldSwitch = SimpleTimeMark.farPast() + eventEndTime = SimpleTimeMark.farPast() + + lastSentEvent = null + } + + @SubscribeEvent + fun onBossbarChange(event: BossbarUpdateEvent) { + if (!isEnabled()) return + if (lastWorldSwitch.passedSince() < 2.seconds) return + if (!eventEndTime.isInPast()) { + return + } + + bossbarPassivePattern.matchMatcher(event.bossbar) { + sendData(group("event"), group("time")) + } + bossbarActivePattern.matchMatcher(event.bossbar) { + sendData(group("event"), group("time")) + } + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + + eventStartedPattern.matchMatcher(event.message) { + sendData(group("event"), null) + } + eventEndedPattern.matchMatcher(event.message) { + lastSentEvent = null + } + } + + private fun sendData(eventName: String, time: String?) { + val eventType = MiningEvent.fromBossbarName(eventName) + if (lastSentEvent == eventType) return + if (eventType == null) { + ErrorManager.logErrorWithData( + Exception("UnknownMiningEvent"), "Unknown mining event detected from string $eventName", + "eventName" to eventName, + "bossbar" to BossbarData.getBossbar(), + "serverType" to LorenzUtils.skyBlockIsland, + "fromChat" to (time == null) + ) + return + } + lastSentEvent = eventType + + val timeRemaining = if (time == null) { + eventType.defaultLength + } else { + TimeUtils.getDuration(time) + } + eventEndTime = SimpleTimeMark.now() + timeRemaining + + val serverId = HypixelData.getCurrentServerId() + if (serverId == null) { + ErrorManager.logErrorWithData( + Exception("NoServerId"), "Could not find server id", + "islandType" to LorenzUtils.skyBlockIsland, + "tablist" to TabListData.getTabList(), + "scoreboard" to ScoreboardData.sidebarLinesFormatted + ) + return + } + + val miningEventData = MiningEventData( + LorenzUtils.skyBlockIsland, + serverId, + eventType, + timeRemaining.inWholeMilliseconds, + LorenzUtils.getPlayerUuid() + ) + val miningEventJson = ConfigManager.gson.toJson(miningEventData) +// //todo remove +// println("\n```json$miningEventJson```") + SkyHanniMod.coroutineScope.launch { + sendData(miningEventJson) + } + } + + private fun isEnabled() = (IslandType.DWARVEN_MINES.isInIsland() || IslandType.CRYSTAL_HOLLOWS.isInIsland()) && config.sendData +// && config.enabled + + + private fun sendData(json: String) { + val response = APIUtil.postJSON("https://api.soopy.dev/skyblock/chevents/set", json) + if (!response.success) return + val success = response.data.getBoolean("success") + if (!success) { + val cause = response.data.getStringOrValue("cause", "unknown") + ErrorManager.logErrorWithData( + Exception("PostFailure"), "Sending mining event data was unsuccessful", + "cause" to cause, + "sentData" to json + ) + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/powdertracker/PowderTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/powdertracker/PowderTracker.kt index a328d12ce..3c3b0dfd3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/powdertracker/PowderTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/powdertracker/PowderTracker.kt @@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.features.mining.powdertracker import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.config.features.mining.PowderTrackerConfig.PowderDisplayEntry +import at.hannibal2.skyhanni.data.BossbarData import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.GuiRenderEvent @@ -23,7 +24,6 @@ import at.hannibal2.skyhanni.utils.tracker.TrackerData import com.google.gson.JsonArray import com.google.gson.JsonNull import com.google.gson.annotations.Expose -import net.minecraft.entity.boss.BossStatus import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.concurrent.fixedRateTimer @@ -153,8 +153,8 @@ object PowderTracker { fun onTick(event: LorenzTickEvent) { if (!isEnabled()) return if (event.repeatSeconds(1)) { - doublePowder = powderBossBarPattern.matcher(BossStatus.bossName).find() - powderBossBarPattern.matchMatcher(BossStatus.bossName) { + doublePowder = powderBossBarPattern.matcher(BossbarData.getBossbar()).find() + powderBossBarPattern.matchMatcher(BossbarData.getBossbar()) { powderTimer = group("time") doublePowder = powderTimer != "00:00" diff --git a/src/main/java/at/hannibal2/skyhanni/test/command/CopyBossbarCommand.kt b/src/main/java/at/hannibal2/skyhanni/test/command/CopyBossbarCommand.kt new file mode 100644 index 000000000..cac3ac02f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/test/command/CopyBossbarCommand.kt @@ -0,0 +1,20 @@ +package at.hannibal2.skyhanni.test.command + +import at.hannibal2.skyhanni.data.BossbarData +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.OSUtils +import at.hannibal2.skyhanni.utils.StringUtils.removeColor + +object CopyBossbarCommand { + fun command(args: Array<String>) { + val noFormattingCodes = args.size == 1 && args[0] == "true" + val bossbarName = if (noFormattingCodes) BossbarData.getBossbar().removeColor() else BossbarData.getBossbar() + val status = if (noFormattingCodes) "without" else "with" + if (bossbarName.isBlank()) { + LorenzUtils.chat("Boss bar appears to be blank.") + } else { + OSUtils.copyToClipboard(bossbarName) + LorenzUtils.chat("Boss bar name copied to clipboard $status formatting codes!") + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt index 43f262d5b..2fd634d26 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt @@ -6,6 +6,7 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.gson.JsonSyntaxException +import org.apache.http.HttpEntity import org.apache.http.client.config.RequestConfig import org.apache.http.client.methods.HttpGet import org.apache.http.client.methods.HttpPost @@ -26,6 +27,8 @@ object APIUtil { private val parser = JsonParser() private var showApiErrors = false + data class ApiResponse(val success: Boolean, val message: String?, val data: JsonObject) + private val builder: HttpClientBuilder = HttpClients.custom().setUserAgent("SkyHanni/${SkyHanniMod.version}") .setDefaultHeaders( @@ -97,23 +100,26 @@ object APIUtil { return JsonObject() } - fun postJSONIsSuccessful(urlString: String, body: String, silentError: Boolean = false): Boolean { + fun postJSON(urlString: String, body: String, silentError: Boolean = false): ApiResponse { val client = builder.build() + try { val method = HttpPost(urlString) method.entity = StringEntity(body, ContentType.APPLICATION_JSON) client.execute(method).use { response -> val status = response.statusLine + val entity = response.entity - if (status.statusCode >= 200 || status.statusCode < 300) { - return true + if (status.statusCode in 200..299) { + val data = readResponse(entity) + return ApiResponse(true, "Request successful", data) } - println("POST request to '$urlString' returned status ${status.statusCode}") - LorenzUtils.error("SkyHanni ran into an error whilst sending data. Status: ${status.statusCode}") - - return false + val message = "POST request to '$urlString' returned status ${status.statusCode}" + println(message) + LorenzUtils.error("SkyHanni ran into an error. Status: ${status.statusCode}") + return ApiResponse(false, message, JsonObject()) } } catch (throwable: Throwable) { if (silentError) { @@ -122,9 +128,26 @@ object APIUtil { throwable.printStackTrace() LorenzUtils.error("SkyHanni ran into an ${throwable::class.simpleName ?: "error"} whilst sending a resource. See logs for more details.") } + return ApiResponse(false, throwable.message, JsonObject()) } finally { client.close() } + } + + private fun readResponse(entity: HttpEntity): JsonObject { + val retSrc = EntityUtils.toString(entity) + return parser.parse(retSrc) as JsonObject + } + + fun postJSONIsSuccessful(urlString: String, body: String, silentError: Boolean = false): Boolean { + val response = postJSON(urlString, body, silentError) + + if (response.success) { + return true + } + + println(response.message) + LorenzUtils.error(response.message ?: "An error occurred during the API request") return false } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt index f9a279c46..e9d755fab 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.utils import com.google.gson.Gson import com.google.gson.JsonElement +import com.google.gson.JsonObject import java.io.Reader import kotlin.reflect.jvm.javaType import kotlin.reflect.typeOf @@ -12,3 +13,27 @@ inline fun <reified T : Any> Gson.fromJson(jsonElement: JsonElement): T = this.fromJson(jsonElement, typeOf<T>().javaType) inline fun <reified T : Any> Gson.fromJson(reader: Reader): T = this.fromJson(reader, typeOf<T>().javaType) + +fun JsonObject.getBoolean(key: String): Boolean { + return if (has(key)) { + try { + get(key).asBoolean + } catch (_: Exception) { + false + } + } else { + false + } +} + +fun JsonObject.getStringOrValue(key: String, alternative: String): String { + return if (has(key)) { + try { + get(key).asString + } catch (_: Exception) { + alternative + } + } else { + alternative + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt b/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt index 3aa432cde..3e1919d8b 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt @@ -124,7 +124,8 @@ class MinecraftConsoleFilter(private val loggerConfigName: String) : Filter { val first = cause.stackTrace[0] val firstName = first.toString() if (firstName == "net.minecraft.scoreboard.Scoreboard.removeTeam(Scoreboard.java:229)" || - firstName == "net.minecraft.scoreboard.Scoreboard.removeTeam(Scoreboard.java:262)" + firstName == "net.minecraft.scoreboard.Scoreboard.removeTeam(Scoreboard.java:262)" || + firstName == "net.minecraft.scoreboard.Scoreboard.removeTeam(Scoreboard.java:240)" ) { filterConsole("NullPointerException at Scoreboard.removeTeam") return Filter.Result.DENY @@ -134,7 +135,8 @@ class MinecraftConsoleFilter(private val loggerConfigName: String) : Filter { return Filter.Result.DENY } if (firstName == "net.minecraft.scoreboard.Scoreboard.removeObjective(Scoreboard.java:179)" || - firstName == "net.minecraft.scoreboard.Scoreboard.removeObjective(Scoreboard.java:198)" + firstName == "net.minecraft.scoreboard.Scoreboard.removeObjective(Scoreboard.java:198)" || + firstName == "net.minecraft.scoreboard.Scoreboard.removeObjective(Scoreboard.java:186)" ) { filterConsole("IllegalArgumentException at Scoreboard.removeObjective") return Filter.Result.DENY |