Skip to content

Commit

Permalink
Refactored a bunch and patched some bugs
Browse files Browse the repository at this point in the history
- Fixed GUI resetting when window is resized
- Fixed a crash when the reward was a mystery box
- RewardCards and Sessions are now constructed within the appropriate classes

Signed-off-by: Dance-Dog <[email protected]>
  • Loading branch information
Dance-Dog committed Apr 2, 2020
1 parent 070cb8a commit 581c411
Show file tree
Hide file tree
Showing 16 changed files with 490 additions and 409 deletions.
44 changes: 17 additions & 27 deletions src/main/java/me/dancedog/rewardclaim/RewardListener.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package me.dancedog.rewardclaim;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
Expand Down Expand Up @@ -31,7 +29,7 @@ public class RewardListener {
"§r§6Click the link to visit our website and claim your reward: §r§bhttp://rewards\\.hypixel\\.net/claim-reward/([A-Za-z0-9]+)§r");

private long lastRewardOpenedMs = new Date().getTime();
private final AtomicReference<JsonObject> rawRewardSessionData = new AtomicReference<>();
private final AtomicReference<RewardSession> sessionData = new AtomicReference<>();

/**
* Fetches & scrapes the reward page in a separate thread. The resulting json is then stored in
Expand All @@ -45,11 +43,12 @@ private void fetchRewardSession(String sessionId) {
try {
URL url = new URL("https://rewards.hypixel.net/claim-reward/" + sessionId);
Response response = new Request(url, Method.GET, null).execute();

if (response.getStatusCode() >= 200 && response.getStatusCode() < 300) {
Document document = Jsoup.parse(response.getBody());
JsonObject rawRewardData = RewardScraper.parseRewardPage(document);
rawRewardData.addProperty("_cookie", response.getNewCookies());
rawRewardSessionData.set(rawRewardData);
RewardSession session = RewardScraper
.parseSessionFromRewardPage(document, response.getNewCookies());
sessionData.set(session);
} else {
Mod.printWarning("Server sent back a " + response.getStatusCode()
+ " status code. Received the following body:\n" + response.getBody(), null, false);
Expand All @@ -67,28 +66,18 @@ private void fetchRewardSession(String sessionId) {
*/
@SubscribeEvent
public void onClientTick(ClientTickEvent event) {
if (rawRewardSessionData.get() != null) {
JsonElement error = rawRewardSessionData.get().get("error");
if (error != null) {
Mod.printWarning("Failed to get reward: " + error.getAsString(), null, true);
if (Minecraft.getMinecraft().theWorld == null) {
return;
}

RewardSession currentSessionData = sessionData.getAndSet(null);
if (currentSessionData != null) {
if (currentSessionData.getError() != null) {
Mod.printWarning("Failed to get reward: " + currentSessionData.getError(), null, true);
return;
}
try {
RewardSession session = SessionDataParser
.parseRewardSessionData(rawRewardSessionData.get());
if (session != null) {
Minecraft.getMinecraft()
.displayGuiScreen(new GuiScreenRewardSession(session));
}
} catch (Exception e) {
Mod.printWarning(
"Oops! We had some trouble reading your daily reward data. Please report this to the mod author with a screenshot of your daily reward page.",
null, true);
Mod.printWarning(e.getClass().getName() + " at " + e.getStackTrace()[0].toString(), e,
true);
} finally {
rawRewardSessionData.set(null);
}
Minecraft.getMinecraft()
.displayGuiScreen(new GuiScreenRewardSession(currentSessionData));
}
}

Expand All @@ -115,7 +104,8 @@ public void onChatReceived(ClientChatReceivedEvent event) {
@SubscribeEvent
public void onGuiInit(GuiOpenEvent event) {
// Check for the reward book notification up to 10 seconds after the reward's chat link was received
if (event.gui instanceof GuiScreenBook
if (Minecraft.getMinecraft().thePlayer != null
&& event.gui instanceof GuiScreenBook
&& (System.currentTimeMillis() - lastRewardOpenedMs) <= 10000) {
event.setCanceled(true);
lastRewardOpenedMs = 0;
Expand Down
84 changes: 53 additions & 31 deletions src/main/java/me/dancedog/rewardclaim/RewardScraper.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package me.dancedog.rewardclaim;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import me.dancedog.rewardclaim.model.RewardSession;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

Expand All @@ -18,53 +17,76 @@ class RewardScraper {

private static final Pattern CSRF_TOKEN_PATTERN = Pattern
.compile("window\\.securityToken = ['\"](.*?)['\"]");
private static final Pattern REWARD_JSON_PATTERN = Pattern
private static final Pattern SESSION_JSON_PATTERN = Pattern
.compile("window\\.appData = ['\"](.*?})['\"]");
private static final JsonParser jsonParser = new JsonParser();

/**
* Read the reward session json from a daily reward page
* Parse the session data from a daily reward page
*
* @param document Document to get the session json from
* @return JsonObject of the session data on the provided document, or null if
* @throws JsonParseException If the document's session data was not valid json
* @throws IllegalStateException If the document's session data was not a JsonObject
* @param document Document representing the reward page
* @param cookie Cookie to be passed into the returned session (used to make claim request)
* @return The session parsed from the provided page
*/
static JsonObject parseRewardPage(Document document) {
static RewardSession parseSessionFromRewardPage(Document document, String cookie) {
JsonObject rawSessionData;

if (document == null || document.body() == null) {
return createErrorJson("Document was null");
}
Element infoScript = document.body().selectFirst("script");
if (infoScript == null) {
return createErrorJson("Unable to locate reward data");
rawSessionData = createErrorJson("Document was null");

} else {
// The "props" script contains information useful the daily reward react app
// This includes the rewards data, csrf token, i18n messages, etc
Element propsScript = document.body().selectFirst("script");
if (propsScript == null) {
rawSessionData = createErrorJson("Unable to locate reward data");

} else {
String propsScriptContents = propsScript.data();
rawSessionData = getRawSessionData(propsScriptContents);
rawSessionData.addProperty("_csrf", getCsrfToken(propsScriptContents));
}
}
JsonObject data = new JsonObject();
return new RewardSession(rawSessionData, cookie);
}

// Get the JSON data for the reward session
String infoScriptContents = infoScript.data();
Matcher rewardJsonMatcher = REWARD_JSON_PATTERN.matcher(infoScriptContents);
/**
* Extract the reward session's json data from the prop script's contents
*
* @param propsScriptContents String contents of the prop script element
* @return JsonObject of the session's data, or a JsonObject containing an error message if none
* was found
*/
private static JsonObject getRawSessionData(String propsScriptContents) {
Matcher rewardJsonMatcher = SESSION_JSON_PATTERN.matcher(propsScriptContents);
if (rewardJsonMatcher.find()) {
JsonObject parsedRewardJson = jsonParser.parse(rewardJsonMatcher.group(1)).getAsJsonObject();
JsonElement errorMessage = parsedRewardJson.get("error");
if (errorMessage != null) {
return createErrorJson(errorMessage.getAsString());
}
data.add("session_data", parsedRewardJson);
return jsonParser.parse(rewardJsonMatcher.group(1)).getAsJsonObject();
} else {
return createErrorJson("Unable to locate reward data");
}
}

// Get the CSRF token needed to claim the reward
Matcher csrfTokenMatcher = CSRF_TOKEN_PATTERN.matcher(infoScriptContents);
/**
* Extract the csrf token from the prop script's contents
*
* @param propsScriptContents String contents of the prop script element
* @return Csrf token string, or null if none was found
*/
private static String getCsrfToken(String propsScriptContents) {
Matcher csrfTokenMatcher = CSRF_TOKEN_PATTERN.matcher(propsScriptContents);
if (csrfTokenMatcher.find()) {
data.addProperty("csrf_token", csrfTokenMatcher.group(1));
} else {
return createErrorJson("Unable to locate csrf token");
return csrfTokenMatcher.group(1);
}

return data;
return null;
}

/**
* Utility method to create a JsonObject containing an error message (same format that rewards
* page uses)
*
* @param errorMsg
* @return JsonObject containing the message
*/
private static JsonObject createErrorJson(String errorMsg) {
JsonObject json = new JsonObject();
json.addProperty("error", errorMsg);
Expand Down
Loading

0 comments on commit 581c411

Please sign in to comment.