aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-01-10 20:05:21 +0100
committerLinnea Gräf <nea@nea.moe>2024-01-10 20:26:02 +0100
commitdf4f308005528111f8417c03efe95f1c2cee36bd (patch)
tree875398ea290099505e299f234b405b126460864c
parent5eb0881e1b470d33a8e02f7d877f9b225516789b (diff)
downloadNotEnoughUpdates-df4f308005528111f8417c03efe95f1c2cee36bd.tar.gz
NotEnoughUpdates-df4f308005528111f8417c03efe95f1c2cee36bd.tar.bz2
NotEnoughUpdates-df4f308005528111f8417c03efe95f1c2cee36bd.zip
Add crash recovery page to PV
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrashRecoveryPage.java147
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java105
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt8
3 files changed, 227 insertions, 33 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrashRecoveryPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrashRecoveryPage.java
new file mode 100644
index 00000000..d68f4a26
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrashRecoveryPage.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2024 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import io.github.moulberry.moulconfig.internal.ClipboardUtils;
+import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import lombok.val;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.crash.CrashReport;
+import net.minecraft.init.Bootstrap;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+public class CrashRecoveryPage extends GuiProfileViewerPage {
+ private final Exception exception;
+ private final String timestamp;
+ private final GuiProfileViewer.ProfileViewerPage lastViewedPage;
+ private int offset = 0;
+ private final CrashReport crashReport;
+
+ public CrashRecoveryPage(
+ GuiProfileViewer instance,
+ Exception exception,
+ GuiProfileViewer.ProfileViewerPage lastViewedPage
+ ) {
+ super(instance);
+ this.lastViewedPage = lastViewedPage;
+ this.timestamp = DateTimeFormatter.ISO_ZONED_DATE_TIME.format(OffsetDateTime.ofInstant(
+ Instant.now(),
+ ZoneId.systemDefault()
+ ));
+ this.exception = exception;
+ val profile = GuiProfileViewer.getProfile();
+ crashReport = new CrashReport("NEU Profile Viewer crashed", exception);
+ val parameters = crashReport.makeCategory("Profile Viewer Parameters");
+
+ parameters.addCrashSection("Viewed Player", (profile == null ? "null" : profile.getUuid()));
+ parameters.addCrashSection("Viewed Profile", GuiProfileViewer.getProfileName());
+ parameters.addCrashSection("Timestamp", timestamp);
+ parameters.addCrashSection("Last Viewed Page", lastViewedPage);
+ Bootstrap.printToSYSOUT(crashReport.getCompleteReport());
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(
+ GuiProfileViewer.getGuiLeft() + getInstance().sizeX / 2f,
+ GuiProfileViewer.getGuiTop() + 20,
+ 0
+ );
+ offset = 20;
+
+ drawTitle();
+
+ drawString("§cLooked like your profile viewer crashed.");
+ drawString("§cPlease immediately send a screenshot of this screen into #neu-support.");
+ drawString("§cJoin our support server at §adiscord.gg/moulberry§c.");
+
+ val profile = GuiProfileViewer.getProfile();
+ drawString("Viewed Player: " + (profile == null ? "null" : profile.getUuid()));
+ drawString("Viewed Profile: " + GuiProfileViewer.getProfileName());
+ drawString("Timestamp: " + timestamp);
+
+ drawString("");
+ drawString(exception.toString());
+ for (StackTraceElement stackTraceElement : exception.getStackTrace()) {
+ if (offset >= getInstance().sizeY - 50) break;
+ drawString(stackTraceElement.toString());
+ }
+
+ GlStateManager.popMatrix();
+
+ val buttonCoords = getButtonCoordinates();
+ RenderUtils.drawFloatingRectWithAlpha(
+ buttonCoords.getX(), buttonCoords.getY(),
+ buttonCoords.getWidth(), buttonCoords.getHeight(),
+ 100, true
+ );
+ Utils.drawStringCenteredScaledMaxWidth(
+ "Copy Report",
+ buttonCoords.getCenterX(),
+ buttonCoords.getCenterY(),
+ false,
+ buttonCoords.getWidth(),
+ -1
+ );
+
+ }
+
+ @Override
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ if (getButtonCoordinates().contains(mouseX, mouseY) && mouseButton == 0) {
+ ClipboardUtils.copyToClipboard(crashReport.getCompleteReport());
+ }
+ return super.mouseClicked(mouseX, mouseY, mouseButton);
+ }
+
+ private Rectangle getButtonCoordinates() {
+ return new Rectangle(
+ GuiProfileViewer.getGuiLeft() + getInstance().sizeX / 2 - 40,
+ GuiProfileViewer.getGuiTop() + getInstance().sizeY - 30,
+ 80, 12
+ );
+ }
+
+ private void drawString(String text) {
+ Utils.drawStringCenteredScaledMaxWidth(text, 0, 0, false, getInstance().sizeX - 20, -1);
+ val spacing = Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT + 2;
+ GlStateManager.translate(0, spacing, 0);
+ offset += spacing;
+ }
+
+ private void drawTitle() {
+ GlStateManager.pushMatrix();
+ GlStateManager.scale(2, 2, 2);
+ Utils.drawStringCenteredScaledMaxWidth("§cKA-BOOM!", 0, 0, false, getInstance().sizeX / 2, -1);
+ GlStateManager.popMatrix();
+ val spacing = Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT * 2 + 6;
+ GlStateManager.translate(0, spacing, 0);
+ offset += spacing;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
index 86db77ca..faff8c5f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -195,23 +195,28 @@ public class GuiProfileViewer extends GuiScreen {
playerNameTextField = new GuiElementTextField(getDisplayName(), GuiElementTextField.SCALE_TEXT);
playerNameTextField.setSize(100, 20);
- if (currentPage == ProfileViewerPage.LOADING) {
+ if (currentPage.isTransient()) {
currentPage = ProfileViewerPage.BASIC;
}
- pages.put(ProfileViewerPage.BASIC, new BasicPage(this));
- pages.put(ProfileViewerPage.DUNGEON, new DungeonPage(this));
- pages.put(ProfileViewerPage.EXTRA, new ExtraPage(this));
- pages.put(ProfileViewerPage.INVENTORIES, new InventoriesPage(this));
- pages.put(ProfileViewerPage.COLLECTIONS, new CollectionsPage(this));
- pages.put(ProfileViewerPage.PETS, new PetsPage(this));
- pages.put(ProfileViewerPage.MINING, new MiningPage(this));
- pages.put(ProfileViewerPage.BINGO, new BingoPage(this));
- pages.put(ProfileViewerPage.TROPHY_FISH, new TrophyFishPage(this));
- pages.put(ProfileViewerPage.BESTIARY, new BestiaryPage(this));
- pages.put(ProfileViewerPage.CRIMSON_ISLE, new CrimsonIslePage(this));
- pages.put(ProfileViewerPage.MUSEUM, new MuseumPage(this));
- pages.put(ProfileViewerPage.RIFT, new RiftPage(this));
+ try {
+ pages.put(ProfileViewerPage.BASIC, new BasicPage(this));
+ pages.put(ProfileViewerPage.DUNGEON, new DungeonPage(this));
+ pages.put(ProfileViewerPage.EXTRA, new ExtraPage(this));
+ pages.put(ProfileViewerPage.INVENTORIES, new InventoriesPage(this));
+ pages.put(ProfileViewerPage.COLLECTIONS, new CollectionsPage(this));
+ pages.put(ProfileViewerPage.PETS, new PetsPage(this));
+ pages.put(ProfileViewerPage.MINING, new MiningPage(this));
+ pages.put(ProfileViewerPage.BINGO, new BingoPage(this));
+ pages.put(ProfileViewerPage.TROPHY_FISH, new TrophyFishPage(this));
+ pages.put(ProfileViewerPage.BESTIARY, new BestiaryPage(this));
+ pages.put(ProfileViewerPage.CRIMSON_ISLE, new CrimsonIslePage(this));
+ pages.put(ProfileViewerPage.MUSEUM, new MuseumPage(this));
+ pages.put(ProfileViewerPage.RIFT, new RiftPage(this));
+ } catch (Exception ex) {
+ pages.put(ProfileViewerPage.CRASH_RECOVERY, new CrashRecoveryPage(this, ex, currentPage));
+ currentPage = ProfileViewerPage.CRASH_RECOVERY;
+ }
}
public static int getGuiLeft() {
@@ -240,15 +245,17 @@ public class GuiProfileViewer extends GuiScreen {
if (startTime == 0) startTime = currentTime;
ProfileViewerPage page = currentPage;
- if (profile == null) {
- page = ProfileViewerPage.INVALID_NAME;
- } else if (profile.getOrLoadSkyblockProfiles(null) == null) {
- page = ProfileViewerPage.LOADING;
- }
+ if (page == ProfileViewerPage.CRASH_RECOVERY) {
+ if (profile == null) {
+ page = ProfileViewerPage.INVALID_NAME;
+ } else if (profile.getOrLoadSkyblockProfiles(null) == null) {
+ page = ProfileViewerPage.LOADING;
+ }
- if (profile != null && profile.getLatestProfileName() == null &&
- !profile.getUpdatingSkyblockProfilesState().get()) {
- page = ProfileViewerPage.NO_SKYBLOCK;
+ if (profile != null && profile.getLatestProfileName() == null &&
+ !profile.getUpdatingSkyblockProfilesState().get()) {
+ page = ProfileViewerPage.NO_SKYBLOCK;
+ }
}
if (profile != null) {
@@ -267,7 +274,8 @@ public class GuiProfileViewer extends GuiScreen {
if (NotEnoughUpdates.INSTANCE.config.profileViewer.alwaysShowBingoTab) {
showBingoPage = true;
} else {
- showBingoPage = selectedProfile != null && selectedProfile.getGamemode() != null && selectedProfile.getGamemode().equals("bingo");
+ showBingoPage = selectedProfile != null && selectedProfile.getGamemode() != null &&
+ selectedProfile.getGamemode().equals("bingo");
}
if (!showBingoPage && currentPage == ProfileViewerPage.BINGO) {
@@ -322,7 +330,10 @@ public class GuiProfileViewer extends GuiScreen {
if (selectedProfile != null && selectedProfile.getGamemode() != null) {
GlStateManager.color(1, 1, 1, 1);
- ResourceLocation gamemodeIcon = gamemodeToIcon.getOrDefault(selectedProfile.getGamemode(), gamemodeIconUnknown);
+ ResourceLocation gamemodeIcon = gamemodeToIcon.getOrDefault(
+ selectedProfile.getGamemode(),
+ gamemodeIconUnknown
+ );
Minecraft.getMinecraft().getTextureManager().bindTexture(gamemodeIcon);
Utils.drawTexturedRect(guiLeft - 16 - 5, guiTop + sizeY + 5, 16, 16, GL11.GL_NEAREST);
}
@@ -394,7 +405,10 @@ public class GuiProfileViewer extends GuiScreen {
if (selectedProfile != null && selectedProfile.getGamemode() != null) {
GlStateManager.color(1, 1, 1, 1);
- ResourceLocation gamemodeIcon = gamemodeToIcon.getOrDefault(selectedProfile.getGamemode(), gamemodeIconUnknown);
+ ResourceLocation gamemodeIcon = gamemodeToIcon.getOrDefault(
+ selectedProfile.getGamemode(),
+ gamemodeIconUnknown
+ );
Minecraft.getMinecraft().getTextureManager().bindTexture(gamemodeIcon);
Utils.drawTexturedRect(
guiLeft - 16 - 5,
@@ -412,7 +426,14 @@ public class GuiProfileViewer extends GuiScreen {
GlStateManager.color(1, 1, 1, 1);
if (pages.containsKey(page)) {
- pages.get(page).drawPage(mouseX, mouseY, partialTicks);
+ try {
+ pages.get(page).drawPage(mouseX, mouseY, partialTicks);
+ } catch (Exception ex) {
+ if (page == ProfileViewerPage.CRASH_RECOVERY)
+ throw ex; // Rethrow if the exception handler crashes.
+ pages.put(ProfileViewerPage.CRASH_RECOVERY, new CrashRecoveryPage(this, ex, currentPage));
+ currentPage = ProfileViewerPage.CRASH_RECOVERY;
+ }
} else {
switch (page) {
case LOADING:
@@ -462,7 +483,8 @@ public class GuiProfileViewer extends GuiScreen {
guiLeft + sizeX / 2f, guiTop + 151, true, 0
);
Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + String.valueOf(EnumChatFormatting.BOLD) + "What are you doing with your life?",
+ EnumChatFormatting.YELLOW + String.valueOf(EnumChatFormatting.BOLD) +
+ "What are you doing with your life?",
guiLeft + sizeX / 2f, guiTop + 161, true, 0
);
if (timeDiff > 600000) {
@@ -691,7 +713,7 @@ public class GuiProfileViewer extends GuiScreen {
}
if (selected) {
- uMin = 196 /256f;
+ uMin = 196 / 256f;
uMax = 226 / 256f;
renderBlurredBackground(width, height, x - 2, y + 2, 30 - 2, 28 - 4);
@@ -746,8 +768,14 @@ public class GuiProfileViewer extends GuiScreen {
}
if (pages.containsKey(currentPage)) {
- if (pages.get(currentPage).mouseClicked(mouseX, mouseY, mouseButton)) {
- return;
+ try {
+ if (pages.get(currentPage).mouseClicked(mouseX, mouseY, mouseButton)) {
+ return;
+ }
+ } catch (Exception ex) {
+ if (currentPage == ProfileViewerPage.CRASH_RECOVERY) throw ex;
+ pages.put(ProfileViewerPage.CRASH_RECOVERY, new CrashRecoveryPage(this, ex, currentPage));
+ currentPage = ProfileViewerPage.CRASH_RECOVERY;
}
}
@@ -865,7 +893,13 @@ public class GuiProfileViewer extends GuiScreen {
super.keyTyped(typedChar, keyCode);
if (pages.containsKey(currentPage)) {
- pages.get(currentPage).keyTyped(typedChar, keyCode);
+ try {
+ pages.get(currentPage).keyTyped(typedChar, keyCode);
+ } catch (Exception ex) {
+ if (currentPage == ProfileViewerPage.CRASH_RECOVERY) throw ex;
+ pages.put(ProfileViewerPage.CRASH_RECOVERY, new CrashRecoveryPage(this, ex, currentPage));
+ currentPage = ProfileViewerPage.CRASH_RECOVERY;
+ }
}
if (playerNameTextField.getFocus()) {
@@ -913,7 +947,9 @@ public class GuiProfileViewer extends GuiScreen {
if (levelObj.maxed) {
renderGoldBar(x, y + 6, xSize);
} else {
- if ((skillName.contains("Catacombs") || Weight.DUNGEON_CLASS_NAMES.stream().anyMatch(e -> skillName.toLowerCase().contains(e))) && levelObj.level >= 50) {
+ if ((skillName.contains("Catacombs") || Weight.DUNGEON_CLASS_NAMES.stream().anyMatch(e -> skillName
+ .toLowerCase()
+ .contains(e))) && levelObj.level >= 50) {
renderGoldBar(x, y + 6, xSize);
} else {
renderBar(x, y + 6, xSize, level % 1);
@@ -1198,6 +1234,7 @@ public class GuiProfileViewer extends GuiScreen {
LOADING(),
INVALID_NAME(),
NO_SKYBLOCK(),
+ CRASH_RECOVERY(),
BASIC(0, Items.paper, "§9Skills"),
DUNGEON(1, Item.getItemFromBlock(Blocks.deadbush), "§eDungeoneering"),
EXTRA(2, Items.book, "§7Profile Stats"),
@@ -1242,6 +1279,10 @@ public class GuiProfileViewer extends GuiScreen {
return null;
}
+ public boolean isTransient() {
+ return this == LOADING || this == NO_SKYBLOCK || this == INVALID_NAME || this == CRASH_RECOVERY;
+ }
+
public Optional<ItemStack> getItem() {
return Optional.ofNullable(stack);
}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt
index d44b7721..1882dac4 100644
--- a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt
@@ -31,6 +31,12 @@ data class Rectangle(
val x: Int, val y: Int,
val width: Int, val height: Int,
) {
+ val centerX: Int
+ get() = x + width / 2
+ val centerY: Int
+ get() = y + height / 2
+
+
/**
* The left edge of this rectangle (Low X)
*/
@@ -69,7 +75,7 @@ data class Rectangle(
/**
* Check if this rectangle contains the given coordinate
*/
- fun contains(x1: Int, y1: Int) :Boolean{
+ fun contains(x1: Int, y1: Int): Boolean {
return left <= x1 && x1 < left + width && top <= y1 && y1 < top + height
}
}