diff options
| author | Gravy Boat <thatgravyboat@gmail.com> | 2021-09-23 19:25:26 -0230 |
|---|---|---|
| committer | Gravy Boat <thatgravyboat@gmail.com> | 2021-09-23 19:25:26 -0230 |
| commit | 7dc51e6f1f280276d782e3c644099758ff01bdb7 (patch) | |
| tree | 89bbbbcc22b100c20e752a750ccef0547c466229 | |
| parent | f71b3ccee2ec9949de7e572375a45dbf1c3fadb8 (diff) | |
| download | RewardClaim-7dc51e6f1f280276d782e3c644099758ff01bdb7.tar.gz RewardClaim-7dc51e6f1f280276d782e3c644099758ff01bdb7.tar.bz2 RewardClaim-7dc51e6f1f280276d782e3c644099758ff01bdb7.zip | |
Initial Commit
21 files changed, 1031 insertions, 29 deletions
diff --git a/build.gradle b/build.gradle index 88b8faf..c5d186a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,13 @@ plugins { id "java" id "com.github.johnrengelman.shadow" version "6.1.0" - id "net.minecraftforge.gradle.forge" version "6f53277" + id "net.minecraftforge.gradle.forge" version "ddb1eb0" + id "org.jetbrains.kotlin.jvm" version "1.5.31" } version = "1.0" -group = "dev.asbyth" -archivesBaseName = "ForgeTemplate" +group = "tech.thatgravyboat" +archivesBaseName = "RewardClaim" sourceCompatibility = targetCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' @@ -19,16 +20,22 @@ minecraft { } configurations { - // Creates an extra configuration that implements `implementation` to be used later as the configuration that shades libraries include implementation.extendsFrom(include) } +repositories { + mavenCentral() + maven { url "https://repo.sk1er.club/repository/maven-public" } + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + maven { url 'https://repo.spongepowered.org/maven' } + maven { url 'https://jitpack.io' } +} + dependencies { - // How to normally add a dependency (If you don't want it to be added to the jar) - // implementation "com.example:example:1.0.0" - // If you would like to include it (have the library inside your jar) instead use - // include "com.example:example:1.0.0" + include 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21' + include "gg.essential:loader-launchwrapper:1.1.1" + implementation "gg.essential:essential-1.8.9-forge:1457" } /** @@ -66,11 +73,22 @@ task moveResources { moveResources.dependsOn processResources classes.dependsOn moveResources -// This adds support to ("embed", "shade", "include") libraries into our JAR +tasks.reobfJar.dependsOn(tasks.shadowJar) + shadowJar { archiveClassifier.set('') configurations = [project.configurations.include] duplicatesStrategy DuplicatesStrategy.EXCLUDE } -jar.dependsOn shadowJar +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs = ['-Xjvm-default=enable'] + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/settings.gradle b/settings.gradle index bac08c3..807a7d2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -25,4 +25,4 @@ pluginManagement { } } -rootProject.name = "ForgeTemplate"
\ No newline at end of file +rootProject.name = "RewardClaim"
\ No newline at end of file diff --git a/src/main/java/dev/asbyth/template/ForgeTemplate.java b/src/main/java/dev/asbyth/template/ForgeTemplate.java deleted file mode 100644 index 959cdbc..0000000 --- a/src/main/java/dev/asbyth/template/ForgeTemplate.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.asbyth.template; - -import net.minecraft.client.Minecraft; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; - -@Mod(modid = "forgetemplate", name = "Forge Template", version = "1.0") -public class ForgeTemplate { - @Mod.EventHandler - public void onFMLInitialization(FMLInitializationEvent event) { - // $USER = The username of the currently logged in user. - // Simply prints out Hello, $USER. - System.out.println("Hello, " + Minecraft.getMinecraft().getSession().getUsername() + "!"); - } -} diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/MappedImageCache.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/MappedImageCache.kt new file mode 100644 index 0000000..e47c649 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/MappedImageCache.kt @@ -0,0 +1,16 @@ +package tech.thatgravyboat.rewardclaim + +import gg.essential.elementa.components.image.ImageCache +import java.awt.image.BufferedImage +import java.net.URL + +object MappedImageCache : ImageCache { + + private val IMAGES = hashMapOf<URL, BufferedImage>() + + override fun get(url: URL) = IMAGES[url] + + override fun set(url: URL, image: BufferedImage) { + IMAGES[url] = image + } +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardClaim.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardClaim.kt new file mode 100644 index 0000000..29628ae --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardClaim.kt @@ -0,0 +1,56 @@ +package tech.thatgravyboat.rewardclaim + +import gg.essential.api.EssentialAPI +import net.minecraft.client.gui.GuiScreenBook +import net.minecraftforge.client.event.ClientChatReceivedEvent +import net.minecraftforge.client.event.GuiOpenEvent +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.event.FMLInitializationEvent +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import tech.thatgravyboat.rewardclaim.ui.RewardClaimGui + +@Mod(name = "RewardClaim", modid = "gravyrewardclaim", version = "1.0.0", modLanguageAdapter = "tech.thatgravyboat.rewardclaim.adapter.KotlinLanguageAdapter") +object ForgeTemplate { + + private var rewardClaimTime: Long = 0 + + @Mod.EventHandler + fun onFMLInitialization(event: FMLInitializationEvent?) { + MinecraftForge.EVENT_BUS.register(this) + } + + @Mod.EventHandler + fun onPreInit(event: FMLPreInitializationEvent?) { + RewardConfiguration.loadData() + } + + @SubscribeEvent + fun onChatMessage(event: ClientChatReceivedEvent) { + val rewardMatcher = RewardConfiguration.rewardMessageRegex.matcher(event.message.unformattedText.trim()) + val rewardMissedMatcher = RewardConfiguration.rewardMissedMessageRegex.matcher(event.message.unformattedText.trim()) + + if (rewardMatcher.matches()) { + EssentialAPI.getGuiUtil().openScreen(RewardClaimGui(rewardMatcher.group("id"))) + rewardClaimTime = System.currentTimeMillis() + } + if (rewardMissedMatcher.matches()) { + EssentialAPI.getNotifications().push( + "Reward Claim Missed!", + "You missed a reward claim, click on this to open the reward claim gui to claim your reward.", + { EssentialAPI.getGuiUtil().openScreen(RewardClaimGui(rewardMissedMatcher.group("id"))) } + ) + event.isCanceled = true + } + } + + @SubscribeEvent + fun onScreen(event: GuiOpenEvent) { + if (EssentialAPI.getGuiUtil().openedScreen() is RewardClaimGui && event.gui is GuiScreenBook && System.currentTimeMillis() - rewardClaimTime <= 3000){ + event.isCanceled = true + rewardClaimTime = 0 + } + } + +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardConfiguration.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardConfiguration.kt new file mode 100644 index 0000000..3d8a79a --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardConfiguration.kt @@ -0,0 +1,49 @@ +package tech.thatgravyboat.rewardclaim + +import com.google.gson.Gson +import com.google.gson.JsonObject +import net.minecraft.util.JsonUtils +import tech.thatgravyboat.rewardclaim.types.RewardImage +import java.io.IOException +import java.net.URL +import java.util.* +import java.util.regex.Pattern + +private val GSON = Gson() + +object RewardConfiguration { + val TEXTURES: MutableMap<String, RewardImage> = HashMap<String, RewardImage>() + var rewardMessageRegex: Pattern = Pattern.compile("Click the link to visit our website and claim your reward: https://rewards\\.hypixel\\.net/claim-reward/(?<id>[A-Za-z0-9]{8})") + var rewardMissedMessageRegex: Pattern = Pattern.compile("We noticed you haven't claimed your free Daily Reward yet!\\nTo choose your reward you have to click the link to visit our website! As a reminder, here's your link for today: https://rewards\\.hypixel\\.net/claim-reward/(?<id>[A-Za-z0-9]{8})") + var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36" + + fun loadData() { + val json = GSON.fromJson(readData(), JsonObject::class.java) + + json.get("textures")?.apply { + for (texture in asJsonArray) { + val image = texture.asJsonObject + TEXTURES[image["id"].asString] = RewardImage(image["url"].asString, JsonUtils.getInt(image, "height", 142)) + } + } + + json.get("rewardRegex")?.apply { rewardMessageRegex = Pattern.compile(asString) } + json.get("missedRewardRegex")?.apply { rewardMissedMessageRegex = Pattern.compile(asString) } + json.get("userAgent")?.apply { userAgent = asString } + } + + private fun readData(): String { + try { + Scanner( + URL("https://gist.githubusercontent.com/ThatGravyBoat/05cf118ea1daced936f040a41a648819/raw/2410c868444b073fd212fbed1da5a063d79dc816/data.json").openStream(), + "UTF-8" + ).use { scanner -> + scanner.useDelimiter("\\A") + return if (scanner.hasNext()) scanner.next() else "" + } + } catch (e: IOException) { + e.printStackTrace() + } + return "" + } +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardLanguage.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardLanguage.kt new file mode 100644 index 0000000..6361bc5 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/RewardLanguage.kt @@ -0,0 +1,20 @@ +package tech.thatgravyboat.rewardclaim + +import java.util.regex.Pattern + +private val TRANSLATION_LINE_REGEX = Pattern.compile("\"(?<key>.*)\": ?\"(?<text>.*)\",?") + +class RewardLanguage(translationDataFromHtml: String) { + + private val translations = hashMapOf<String, String>() + + fun translate(key: String) = translations.getValue(key) + + //We have to do it this way as this is easier than fixing all the things that isn't + //valid in normal json but is valid in javascript objects. Such as escaped single quotes and trailing commas. + init { + TRANSLATION_LINE_REGEX.matcher(translationDataFromHtml.replace("\\'", "'")).apply { + while (find()) translations[group("key")] = group("text") + } + } +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/adapter/KotlinLanguageAdapter.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/adapter/KotlinLanguageAdapter.kt new file mode 100644 index 0000000..11b3188 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/adapter/KotlinLanguageAdapter.kt @@ -0,0 +1,27 @@ +package tech.thatgravyboat.rewardclaim.adapter + +import net.minecraftforge.fml.common.FMLModContainer +import net.minecraftforge.fml.common.ILanguageAdapter +import net.minecraftforge.fml.common.ModContainer +import net.minecraftforge.fml.relauncher.Side +import java.lang.reflect.Field +import java.lang.reflect.Method + +class KotlinLanguageAdapter : ILanguageAdapter { + override fun supportsStatics() = false + + override fun setProxy(target: Field, proxyTarget: Class<*>, proxy: Any) { + target.set(proxyTarget.getDeclaredField("INSTANCE").get(null), proxy) + } + + override fun getNewInstance( + container: FMLModContainer, + objectClass: Class<*>, + classLoader: ClassLoader, + factoryMarkedAnnotation: Method? + ): Any { + return objectClass.fields.find { it.name == "INSTANCE" }?.get(null) ?: objectClass.newInstance() + } + + override fun setInternalProxies(mod: ModContainer?, side: Side?, loader: ClassLoader?) {} +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/GameMode.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/GameMode.kt new file mode 100644 index 0000000..fca199b --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/GameMode.kt @@ -0,0 +1,42 @@ +package tech.thatgravyboat.rewardclaim.types + +@Suppress("unused") +enum class GameMode(val displayName: String) { + ERROR("Error"), + BEDWARS("Bed Wars"), + SKYWARS("SkyWars"), + PROTOTYPE("Prototype"), + SKYBLOCK("SkyBlock"), + MAIN("Main"), + MURDER_MYSTERY("Murder Mystery"), + HOUSING("Housing"), + ARCADE("Arcade"), + BUILD_BATTLE("Build Battle"), + DUELS("Duels"), + PIT("PIT"), + UHC("UHC"), + SPEED_UHC("Speed UHC"), + TNTGAMES("TNT Games"), + LEGACY("Classic"), + QUAKECRAFT("Quakecraft"), + WALLS("Walls"), + PAINTBALL("Paintball"), + VAMPIREZ("VampireZ"), + ARENA("Arena"), + GINGERBREAD("Turbo Kart Racers"), + MCGO("Cops and Crims"), + SURVIVAL_GAMES("Blitz SG"), + WALLS3("Mega Walls"), + SUPER_SMASH("Smash Heroes"), + BATTLEGROUND("Warlords"); + + companion object { + fun getModeFromId(id: String?): GameMode { + return try { + valueOf(id!!) + } catch (e: Exception) { + ERROR + } + } + } +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardData.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardData.kt new file mode 100644 index 0000000..cc89422 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardData.kt @@ -0,0 +1,82 @@ +package tech.thatgravyboat.rewardclaim.types + +import tech.thatgravyboat.rewardclaim.RewardConfiguration +import tech.thatgravyboat.rewardclaim.RewardLanguage +import java.util.* +import java.util.regex.Pattern + + +private val ARMOR_PIECE_REGEX = Pattern.compile("^[a-z0-9_]+_([a-z]+)$", Pattern.CASE_INSENSITIVE) +private val ARMOR_REGEX = Pattern.compile("_([a-z]+)$", Pattern.CASE_INSENSITIVE) + +class RewardData(val rarity: RewardRarity, + private val reward : String, + val amount : Int?, + val boxes : Int?, + private val gameMode : GameMode?, + private val rewardPackage : String?, + private val rewardKey : String? + ) { + + fun getDisplayName(language: RewardLanguage): String { + rewardPackage?.let { item -> + if (reward.equals("housing_package", ignoreCase = true)) { + return "${rarity.color}${language.translate("housing.skull." + item.replace("specialoccasion_reward_card_skull_", ""))}" + } + } + rewardKey?.let { key -> + if (reward.equals("add_vanity", ignoreCase = true)) { + val pieceMatcher = ARMOR_PIECE_REGEX.matcher(key) + val armorMatcher = ARMOR_REGEX.matcher(key) + if ("suit" in key && pieceMatcher.find() && armorMatcher.find()) { + return "${rarity.color}${language.translate("vanity." + armorMatcher.group(1))} ${language.translate("vanity.armor." + pieceMatcher.group(1))}" + } else if ("emote" in key || "taunt" in key) { + return "${rarity.color}${language.translate("vanity.$key")}" + } + } + } + return if (reward.equals("tokens", ignoreCase = true) || reward.equals("coins", ignoreCase = true)) { + "${rarity.color}${language.translate("type.$reward").replace("{\$game}", gameMode!!.displayName)}" + } else { + "${rarity.color}${language.translate("type.$reward")}" + } + } + + fun getDescription(language: RewardLanguage): String { + rewardKey?.let { key -> + if (reward.equals("add_vanity", ignoreCase = true)) { + when { + "suit" in key -> return language.translate("vanity.suits.description") + "emote" in key -> return language.translate("vanity.emotes.description") + "taunt" in key -> return language.translate("vanity.gestures.description") + } + } + } + return if (reward.equals("tokens", ignoreCase = true) || reward.equals("coins", ignoreCase = true)) { + "${rarity.color}${language.translate("type.$reward.description").replace("{\$game}", gameMode!!.displayName)}" + } else { + "${rarity.color}${language.translate("type.$reward.description")}" + } + } + + val image: RewardImage? + get() { + var id = reward.lowercase(Locale.ROOT) + rewardKey?.let { key -> + if (id == "add_vanity") { + when { + "suit" in key -> id += "_suit" + "emote" in key -> id += "_emote" + "taunt" in key -> id += "_taunt" + } + } + } + rewardPackage?.let { item -> + if (id == "housing_package") { + val packageId = item.replace("specialoccasion_reward_card_skull_", "") + RewardConfiguration.TEXTURES[id + "_" + packageId]?.let { image -> return image } + } + } + return RewardConfiguration.TEXTURES[id] + } +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardImage.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardImage.kt new file mode 100644 index 0000000..fc8446a --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardImage.kt @@ -0,0 +1,15 @@ +package tech.thatgravyboat.rewardclaim.types + +import java.net.MalformedURLException +import java.net.URL + +class RewardImage(private val urlString: String, val height: Int) { + val url: URL? + get() { + return try { + URL(urlString) + } catch (ignored: MalformedURLException) { + null + } + } +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardRarity.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardRarity.kt new file mode 100644 index 0000000..d4e45b1 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/RewardRarity.kt @@ -0,0 +1,11 @@ +package tech.thatgravyboat.rewardclaim.types + +import gg.essential.universal.ChatColor +import java.awt.Color + +enum class RewardRarity(val translationKey: String, val color: ChatColor) { + COMMON("rarity.common", ChatColor.WHITE), + RARE("rarity.rare", ChatColor.AQUA), + EPIC("rarity.epic", ChatColor.DARK_PURPLE), + LEGENDARY("rarity.legendary", ChatColor.GOLD); +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/StreakData.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/StreakData.kt new file mode 100644 index 0000000..4a5cb98 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/StreakData.kt @@ -0,0 +1,3 @@ +package tech.thatgravyboat.rewardclaim.types + +class StreakData(val progress : Int, val current : Int, val highest : Int)
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/WebData.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/WebData.kt new file mode 100644 index 0000000..38318d1 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/types/WebData.kt @@ -0,0 +1,60 @@ +package tech.thatgravyboat.rewardclaim.types + +import com.google.gson.Gson +import com.google.gson.JsonObject +import net.minecraft.util.JsonUtils +import tech.thatgravyboat.rewardclaim.RewardLanguage +import java.util.regex.Matcher + +private val GSON = Gson() + +class WebData(security : Matcher, data : Matcher, i18n : Matcher) { + + val securityToken : String = security.group("token") + val language : RewardLanguage = RewardLanguage(i18n.group("translations")) + + val rewards = mutableListOf<RewardData>() + var streak : StreakData = StreakData(0,0,0) + var activeAd : Int = 0 + var adLink : String = "https://store.hypixel.net/?utm_source=rewards-video&utm_medium=website&utm_content=TRsCiBNYY7M&utm_campaign=Rewards" + var skippable : Boolean = false + var duration : Int = 30 + + init { + val json = GSON.fromJson(data.group("data"), JsonObject::class.java) + json.get("rewards")?.let { + if (it.isJsonArray) { + it.asJsonArray.forEach { jsonObject -> + val rewardObject = jsonObject.asJsonObject + rewards.add(RewardData( + RewardRarity.valueOf(rewardObject.get("rarity").asString!!), + rewardObject.get("reward").asString!!, + if (rewardObject.has("amount")) rewardObject.get("amount").asInt else null, + if (rewardObject.has("intlist")) rewardObject.get("intlist").asJsonArray.size() else null, + if (rewardObject.has("gameType")) GameMode.getModeFromId(rewardObject.get("gameType").asString) else null, + JsonUtils.getString(rewardObject, "package", null), + JsonUtils.getString(rewardObject, "key", null), + )) + } + } + } + + json.get("dailyStreak")?.let { + val streakObject = it.asJsonObject + streak = StreakData(JsonUtils.getInt(streakObject, "value", 0), + JsonUtils.getInt(streakObject, "score", 0), + JsonUtils.getInt(streakObject, "highScore", 0) + ) + } + + json.get("activeAd")?.let { activeAd = it.asInt } + json.get("ad")?.let { jsonObject -> + val adObject = jsonObject.asJsonObject + adObject.get("link")?.let { adLink = it.asString } + adObject.get("duration")?.let { duration = it.asInt } + } + json.get("skippable")?.let { skippable = it.asBoolean } + + } + +}
\ No newline at end of file diff --git a/src/main/kotlin/tech/thatgravyboat/rewardclaim/ui/RewardClaimGui.kt b/src/main/kotlin/tech/thatgravyboat/rewardclaim/ui/RewardClaimGui.kt new file mode 100644 index 0000000..8f1d535 --- /dev/null +++ b/src/main/kotlin/tech/thatgravyboat/rewardclaim/ui/RewardClaimGui.kt @@ -0,0 +1,308 @@ +package tech.thatgravyboat.rewardclaim.ui + +import gg.essential.api.utils.Multithreading.runAsync +import gg.essential.api.utils.Multithreading.schedule +import gg.essential.elementa.WindowScreen +import gg.essential.elementa.components.* +import gg.essential.elementa.constraints.CenterConstraint +import gg.essential.elementa.dsl.* +import gg.essential.universal.ChatColor +import gg.essential.universal.UDesktop +import gg.essential.vigilance.gui.VigilancePalette +import org.apache.commons.io.IOUtils +import tech.thatgravyboat.rewardclaim.RewardConfiguration +import tech.thatgravyboat.rewardclaim.types.WebData +import java.awt.Color +import java.net.* +import java.nio.charset.Charset +import java.util.concurrent.TimeUnit +import java.util.regex.Matcher +import java.util.regex.Pattern + +private val BUTTON_HOVER = Color(0, 212, 105) + +private val SECURITY_REGEX = Pattern.compile("window\\.securityToken = \"(?<token>.*)\";") +private val DATA_REGEX = Pattern.compile("window\\.appData = '(?<data>\\{.*})';") +private val I18N_REGEX = Pattern.compile("window.i18n = \\{(?<translations>.*)};", Pattern.DOTALL) + +class RewardClaimGui(private val id : String) : WindowScreen() { + + private var state: State = State.LOADING + private var selected = -1 + + //Raw Data + private lateinit var data: WebData + + init { + runAsync(Runnable { + try { + val cookieManager = CookieManager() + CookieHandler.setDefault(cookieManager) + val url = URL("https://rewards.hypixel.net/claim-reward/$id") + (url.openConnection() as HttpURLConnection).apply { + requestMethod = "GET" + useCaches = true + addRequestProperty("User-Agent", RewardConfiguration.userAgent) + readTimeout = 15000 + connectTimeout = 15000 + doOutput = true + inputStream.use { + val html = IOUtils.toString(it, Charset.defaultCharset()) + val securityMatcher: Matcher = SECURITY_REGEX.matcher(html) + val dataMatcher: Matcher = DATA_REGEX.matcher(html) + val i18nMatcher: Matcher = I18N_REGEX.matcher(html) + val securityFound = securityMatcher.find() + val dataFound = dataMatcher.find() + val i18nFound = i18nMatcher.find() + + if (securityFound && dataFound && i18nFound) { + data = WebData(securityMatcher, dataMatcher, i18nMatcher) + + if (data.rewards.isEmpty()) { + state = State.FAILED_REWARDS + errorPopup("Rewards were empty.") + }else { + state = State.SUCCESSFUL + updateElements() + } + + if (data.skippable || data.duration == 0){ + adPopup(true) + }else { + schedule({ adPopup(true) }, data.duration.toLong(), TimeUnit.SECONDS) + } + } else { + state = State.FAILED_REWARDS + errorPopup("Regex could not be found.\nSecurity: $securityFound\nI18n: $i18nFound\nData: $dataFound") + } + } + } + } catch (e: Exception) { + state = State.FAILED + errorPopup("Error: " + e.message) + e.printStackTrace() + } + }) + adPopup(false) + } + + private val background = UIBlock(VigilancePalette.getBackground()).constrain { + width = 100.percent() + height = 100.percent() + } childOf this.window + + private val selectedReward = UISelectedReward(30.percent() - 0.5.pixel()) childOf background + + init { + UIBlock(VigilancePalette.getDivider()).constrain { + width = 1.pixel() + height = 75.percent() + x = 50.percent() - 0.5.pixel() + y = 12.5.percent() + } childOf background + + UIBlock(VigilancePalette.getDivider()).constrain { + width = 1.pixel() + height = 75.percent() + x = 10.percent() - 0.5.pixel() + y = 12.5.percent() + } childOf background + + UIBlock(VigilancePalette.getDivider()).constrain { + width = 30.percent() - 1.pixel() + height = 1.pixel() + x = 15.percent() + y = 70.percent() + } childOf background + + UIText("Click to claim 1 of the 3 Rewards").apply { + constrain { + x = 30.percent() - 0.5.pixel() - (getTextWidth() / 2f).pixel() + y = 15.percent() + } childOf background + } + + UIText("Reward Options").apply { + constrain { + x = 75.percent() - (getTextWidth() / 2f).pixel() + y = 15.percent() + } childOf background + } + + UIText("§lClaim Reward", false).let { text -> + UIBlock(VigilancePalette.getAccent()).let { button -> + button.constrain { + width = text.getTextWidth().pixel() + 18.pixel() + height = 17.pixel() + y = 60.percent() + x = 30.percent() - 0.5.pixel() - (text.getTextWidth() / 2f + 9f).pixel() + } childOf background + + text.constrain { + x = CenterConstraint() + y = CenterConstraint() + } childOf button + + button.onMouseEnter { setColor(BUTTON_HOVER) } + button.onMouseLeave { setColor(VigilancePalette.getAccent()) } + button.onMouseClick { event -> + if (event.mouseButton == 0 && selected != -1) confirmPopup() + event.stopPropagation() + } + } + } + + UIText("Daily Streak").apply { + constrain { + x = 30.percent() - 0.5.pixel() - (getTextWidth() / 2f).pixel() + y = 72.percent() + } childOf background + } + + adPopup(false) + } + + //region Daily Streak + + private val streakSubHeading = UIText(String.format("Current: %d Highest: %d", 0, 0)).apply { + constrain { + x = 30.percent() - 0.5.pixel() - (getTextWidth() / 2f).pixel() + y = 77.percent() + } childOf background + } + + private val streaks = Array(9){ i -> + UICircle(5f, VigilancePalette.getDivider(), 15).let { + it.constrain { + x = ((15.percent() + (15.percent() - 0.5.pixel())) - 45.pixel()) + (it.getWidth() * i).pixel() + y = 83.percent() + } childOf background + } + } + + //endregion + + private val rewards = Array(3){ i -> UIReward(57.5.percent(), 30.percent() + (18 * i).percent()) childOf background}.also { + for (reward in it) { + reward.onMouseClick { event -> + if (event.mouseButton == 0 && state == State.SUCCESSFUL) { + for (j in 0..2) { + it[j].setSelected(it[j] == reward) + if (it[j] != event.currentTarget) continue + selected = j + selectedReward.updateInfo(data.rewards[selected], data.language) + } + } + } + reward.hide(true) + } + } + + private fun updateElements() { + data.let { + for (i in 0 until data.streak.progress) streaks[i].setColor(VigilancePalette.getAccent()) + streakSubHeading.setText(String.format("Current: %d Highest: %d", data.streak.current, data.streak.highest)) + streakSubHeading.setX(30.percent() - 0.5.pixel() - (streakSubHeading.getTextWidth() / 2f).pixel()) + + for (i in 0 until 3) { + rewards[i].let { + it.setData(data.rewards[i], data.language) + it.unhide(true) + } + } + } + } + + private var popup : UIPopup? = nul |
