aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-02-12 02:26:18 +0800
committershedaniel <daniel@shedaniel.me>2022-02-18 11:46:02 +0800
commitc81181f8d6ceb01b995d04026b876b5fe5b86bac (patch)
treef0412dd602231a8590b49f73bf5420c8045f3482 /runtime/src/main/java
parentff5e546de4bca679231e5ca474dc21785622463b (diff)
downloadRoughlyEnoughItems-c81181f8d6ceb01b995d04026b876b5fe5b86bac.tar.gz
RoughlyEnoughItems-c81181f8d6ceb01b995d04026b876b5fe5b86bac.tar.bz2
RoughlyEnoughItems-c81181f8d6ceb01b995d04026b876b5fe5b86bac.zip
Add preliminary crash catcher, close #771
Diffstat (limited to 'runtime/src/main/java')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java7
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java11
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java21
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsEntryListWidget.java192
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java100
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java18
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java36
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java5
8 files changed, 367 insertions, 23 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java
index 3d059b30d..469e6a0f1 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/REIRuntimeImpl.java
@@ -26,6 +26,7 @@ package me.shedaniel.rei.impl.client;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.mojang.blaze3d.platform.Window;
+import com.mojang.blaze3d.systems.RenderSystem;
import me.shedaniel.architectury.event.events.GuiEvent;
import me.shedaniel.architectury.event.events.client.ClientTickEvent;
import me.shedaniel.math.Rectangle;
@@ -241,7 +242,11 @@ public class REIRuntimeImpl implements REIRuntime {
Argument.SEARCH_CACHE.clear();
getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay);
lastDisplayScreen.clear();
- CachedEntryListRender.refresh();
+ if (!RenderSystem.isOnRenderThread()) {
+ RenderSystem.recordRenderCall(CachedEntryListRender::refresh);
+ } else {
+ CachedEntryListRender.refresh();
+ }
}
@Override
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java
index b7c9670d3..ad270d949 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsEntryListWidget.java
@@ -24,7 +24,7 @@
package me.shedaniel.rei.impl.client.gui.credits;
import com.mojang.blaze3d.vertex.PoseStack;
-import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
+import me.shedaniel.clothconfig2.gui.widget.DynamicSmoothScrollingEntryListWidget;
import me.shedaniel.rei.impl.client.gui.text.TextTransformations;
import net.minecraft.ChatFormatting;
import net.minecraft.Util;
@@ -42,8 +42,7 @@ import java.net.URISyntaxException;
import java.util.List;
@ApiStatus.Internal
-public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWidget<CreditsEntryListWidget.CreditsItem> {
-
+public class CreditsEntryListWidget extends DynamicSmoothScrollingEntryListWidget<CreditsEntryListWidget.CreditsItem> {
private boolean inFocus;
public CreditsEntryListWidget(Minecraft client, int width, int height, int startY, int endY) {
@@ -70,8 +69,8 @@ public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWi
clearItems();
}
- private CreditsItem rei_getEntry(int int_1) {
- return this.children().get(int_1);
+ private CreditsItem rei_getEntry(int index) {
+ return this.children().get(index);
}
public void creditsAddEntry(CreditsItem entry) {
@@ -88,7 +87,7 @@ public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWi
return width - 40;
}
- public static abstract class CreditsItem extends DynamicNewSmoothScrollingEntryListWidget.Entry<CreditsItem> {
+ public static abstract class CreditsItem extends DynamicSmoothScrollingEntryListWidget.Entry<CreditsItem> {
}
public static class TextCreditsItem extends CreditsItem {
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java
index 6f576f339..04010bc54 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/credits/CreditsScreen.java
@@ -35,6 +35,8 @@ import net.minecraft.client.gui.components.AbstractButton;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.resources.language.I18n;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.util.Tuple;
@@ -46,7 +48,6 @@ import java.util.stream.Collectors;
@ApiStatus.Internal
public class CreditsScreen extends Screen {
-
private Screen parent;
private AbstractButton buttonDone;
private CreditsEntryListWidget entryListWidget;
@@ -57,12 +58,12 @@ public class CreditsScreen extends Screen {
}
@Override
- public boolean keyPressed(int int_1, int int_2, int int_3) {
- if (int_1 == 256 && this.shouldCloseOnEsc()) {
+ public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
+ if (keyCode == 256 && this.shouldCloseOnEsc()) {
openPrevious();
return true;
}
- return super.keyPressed(int_1, int_2, int_3);
+ return super.keyPressed(keyCode, scanCode, modifiers);
}
@Override
@@ -120,18 +121,18 @@ public class CreditsScreen extends Screen {
}
@Override
- public boolean mouseScrolled(double double_1, double double_2, double double_3) {
- if (entryListWidget.mouseScrolled(double_1, double_2, double_3))
+ public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
+ if (entryListWidget.mouseScrolled(mouseX, mouseY, amount))
return true;
- return super.mouseScrolled(double_1, double_2, double_3);
+ return super.mouseScrolled(mouseX, mouseY, amount);
}
@Override
- public void render(PoseStack matrices, int int_1, int int_2, float float_1) {
+ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
this.renderDirtBackground(0);
- this.entryListWidget.render(matrices, int_1, int_2, float_1);
+ this.entryListWidget.render(matrices, mouseX, mouseY, delta);
drawCenteredString(matrices, this.font, I18n.get("text.rei.credits"), this.width / 2, 16, 16777215);
- super.render(matrices, int_1, int_2, float_1);
+ super.render(matrices, mouseX, mouseY, delta);
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsEntryListWidget.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsEntryListWidget.java
new file mode 100644
index 000000000..33da45a56
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsEntryListWidget.java
@@ -0,0 +1,192 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.error;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.clothconfig2.gui.widget.DynamicEntryListWidget;
+import me.shedaniel.clothconfig2.gui.widget.DynamicSmoothScrollingEntryListWidget;
+import net.minecraft.ChatFormatting;
+import net.minecraft.Util;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiComponent;
+import net.minecraft.client.gui.narration.NarratableEntry;
+import net.minecraft.client.resources.sounds.SimpleSoundInstance;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.sounds.SoundEvents;
+import net.minecraft.util.FormattedCharSequence;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.List;
+
+@ApiStatus.Internal
+public class ErrorsEntryListWidget extends DynamicSmoothScrollingEntryListWidget<ErrorsEntryListWidget.Entry> {
+ private boolean inFocus;
+
+ public ErrorsEntryListWidget(Minecraft client, int width, int height, int startY, int endY) {
+ super(client, width, height, startY, endY, GuiComponent.BACKGROUND_LOCATION);
+ }
+
+ @Override
+ public boolean changeFocus(boolean boolean_1) {
+ if (!this.inFocus && this.getItemCount() == 0) {
+ return false;
+ } else {
+ this.inFocus = !this.inFocus;
+ if (this.inFocus && this.getFocused() == null && this.getItemCount() > 0) {
+ this.moveSelection(1);
+ } else if (this.inFocus && this.getFocused() != null) {
+ this.moveSelection(0);
+ }
+
+ return this.inFocus;
+ }
+ }
+
+ public void _clearItems() {
+ clearItems();
+ }
+
+ private Entry _getEntry(int index) {
+ return this.children().get(index);
+ }
+
+ public void _addEntry(Entry entry) {
+ addItem(entry);
+ }
+
+ @Override
+ public int getItemWidth() {
+ return width - 80;
+ }
+
+ @Override
+ protected int getScrollbarPosition() {
+ return width - 40;
+ }
+
+ public static abstract class Entry extends DynamicEntryListWidget.Entry<Entry> {
+ @Override
+ public List<? extends NarratableEntry> narratables() {
+ return Collections.emptyList();
+ }
+ }
+
+ public static class TextEntry extends Entry {
+ private Component text;
+ private int width;
+ private List<FormattedCharSequence> textSplit;
+
+ public TextEntry(Component text, int width) {
+ this.text = text;
+ this.width = width;
+ this.textSplit = text.getString().trim().isEmpty() ? Collections.singletonList(text.getVisualOrderText()) : Minecraft.getInstance().font.split(text, width - 6);
+ }
+
+ @Override
+ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
+ if (this.width != entryWidth) {
+ this.width = entryWidth;
+ this.textSplit = text.getString().trim().isEmpty() ? Collections.singletonList(text.getVisualOrderText()) : Minecraft.getInstance().font.split(text, width - 6);
+ }
+ int yy = y;
+ for (FormattedCharSequence textSp : textSplit) {
+ Minecraft.getInstance().font.drawShadow(matrices, textSp, x + 5, yy, -1);
+ yy += 12;
+ }
+ }
+
+ @Override
+ public int getItemHeight() {
+ return 12 * textSplit.size();
+ }
+
+ @Override
+ public boolean changeFocus(boolean boolean_1) {
+ return false;
+ }
+ }
+
+ public static class LinkEntry extends Entry {
+ private Component text;
+ private List<FormattedCharSequence> textSplit;
+ private String link;
+ private boolean contains;
+
+ public LinkEntry(Component text, String link, int width) {
+ this.text = text;
+ this.textSplit = Minecraft.getInstance().font.split(text, width - 6);
+ this.link = link;
+ }
+
+ @Override
+ public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
+ contains = mouseX >= x && mouseX <= x + entryWidth && mouseY >= y && mouseY <= y + entryHeight;
+ if (contains) {
+ Minecraft.getInstance().screen.renderTooltip(matrices, new TextComponent("Click to open link."), mouseX, mouseY);
+ int yy = y;
+ for (FormattedCharSequence textSp : textSplit) {
+ FormattedCharSequence underlined = characterVisitor -> {
+ return textSp.accept((charIndex, style, codePoint) -> characterVisitor.accept(charIndex, style.applyFormat(ChatFormatting.UNDERLINE), codePoint));
+ };
+ Minecraft.getInstance().font.drawShadow(matrices, underlined, x + 5, yy, 0xff1fc3ff);
+ yy += 12;
+ }
+ } else {
+ int yy = y;
+ for (FormattedCharSequence textSp : textSplit) {
+ Minecraft.getInstance().font.drawShadow(matrices, textSp, x + 5, yy, 0xff1fc3ff);
+ yy += 12;
+ }
+ }
+ }
+
+ @Override
+ public int getItemHeight() {
+ return 12 * textSplit.size();
+ }
+
+ @Override
+ public boolean changeFocus(boolean boolean_1) {
+ return false;
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (contains && button == 0) {
+ Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
+ try {
+ Util.getPlatform().openUri(new URI(link));
+ return true;
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java
new file mode 100644
index 000000000..db62c7b33
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/error/ErrorsScreen.java
@@ -0,0 +1,100 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.impl.client.gui.error;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.rei.impl.client.gui.error.ErrorsEntryListWidget.TextEntry;
+import net.minecraft.client.gui.chat.NarratorChatListener;
+import net.minecraft.client.gui.components.AbstractButton;
+import net.minecraft.client.gui.components.Button;
+import net.minecraft.client.gui.screens.GenericDirtMessageScreen;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TranslatableComponent;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.List;
+import java.util.function.Function;
+
+@ApiStatus.Internal
+public class ErrorsScreen extends Screen {
+ private List<Object> components;
+ private AbstractButton doneButton;
+ private ErrorsEntryListWidget listWidget;
+
+ public ErrorsScreen(Component title, List<Object> components) {
+ super(title);
+ this.components = components;
+ }
+
+ @Override
+ public boolean shouldCloseOnEsc() {
+ return false;
+ }
+
+ @Override
+ public void init() {
+ addWidget(listWidget = new ErrorsEntryListWidget(minecraft, width, height, 32, height - 32));
+ listWidget._clearItems();
+ for (Object component : components) {
+ if (component instanceof Component) {
+ listWidget._addEntry(new TextEntry((Component) component, listWidget.getItemWidth()));
+ } else {
+ listWidget._addEntry(((Function<Integer, ErrorsEntryListWidget.Entry>) component).apply(listWidget.getItemWidth()));
+ }
+ }
+ listWidget._addEntry(new TextEntry(NarratorChatListener.NO_TITLE, listWidget.getItemWidth()));
+ addRenderableWidget(doneButton = new Button(width / 2 - 100, height - 26, 200, 20, new TranslatableComponent("menu.quit"), button -> exit()));
+ }
+
+ private void exit() {
+ boolean localServer = this.minecraft.isLocalServer();
+ boolean connectedToRealms = this.minecraft.isConnectedToRealms();
+ this.minecraft.level.disconnect();
+
+ if (localServer) {
+ this.minecraft.clearLevel(new GenericDirtMessageScreen(new TranslatableComponent("menu.savingLevel")));
+ } else {
+ this.minecraft.clearLevel();
+ }
+
+ System.exit(-1);
+ }
+
+ @Override
+ public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
+ if (listWidget.mouseScrolled(mouseX, mouseY, amount))
+ return true;
+ return super.mouseScrolled(mouseX, mouseY, amount);
+ }
+
+ @Override
+ public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
+ this.renderDirtBackground(0);
+ this.listWidget.render(matrices, mouseX, mouseY, delta);
+ drawCenteredString(matrices, this.font, getTitle(), this.width / 2, 16, 16777215);
+ super.render(matrices, mouseX, mouseY, delta);
+ }
+
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java
index 1533ba7d8..441d960e9 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/BatchedEntryRendererManager.java
@@ -89,7 +89,8 @@ public class BatchedEntryRendererManager {
} catch (Throwable throwable) {
CrashReport report = CrashReportUtils.essential(throwable, "Adding entry");
CrashReportUtils.renderer(report, currentEntry);
- throw CrashReportUtils.throwReport(report);
+ CrashReportUtils.catchReport(report);
+ return;
}
}
toRender.add(widget);
@@ -163,7 +164,8 @@ public class BatchedEntryRendererManager {
} catch (Throwable throwable) {
CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry background");
CrashReportUtils.renderer(report, entry);
- throw CrashReportUtils.throwReport(report);
+ CrashReportUtils.catchReport(report);
+ return;
}
}
firstRenderer.startBatch(first, extraData[0], matrices, delta);
@@ -177,7 +179,8 @@ public class BatchedEntryRendererManager {
} catch (Throwable throwable) {
CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry base");
CrashReportUtils.renderer(report, entry);
- throw CrashReportUtils.throwReport(report);
+ CrashReportUtils.catchReport(report);
+ return;
}
}
immediate.endBatch();
@@ -191,7 +194,8 @@ public class BatchedEntryRendererManager {
} catch (Throwable throwable) {
CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry base");
CrashReportUtils.renderer(report, entry);
- throw CrashReportUtils.throwReport(report);
+ CrashReportUtils.catchReport(report);
+ return;
}
}
immediate.endBatch();
@@ -205,7 +209,8 @@ public class BatchedEntryRendererManager {
} catch (Throwable throwable) {
CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry extra");
CrashReportUtils.renderer(report, entry);
- throw CrashReportUtils.throwReport(report);
+ CrashReportUtils.catchReport(report);
+ return;
}
}
if (debugTime) time.add(System.nanoTime() - l);
@@ -226,7 +231,8 @@ public class BatchedEntryRendererManager {
} catch (Throwable throwable) {
CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry");
CrashReportUtils.renderer(report, entry);
- throw CrashReportUtils.throwReport(report);
+ CrashReportUtils.catchReport(report);
+ return;
}
}
}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java
new file mode 100644
index 000000000..1015160f8
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/CatchingExceptionUtils.java
@@ -0,0 +1,36 @@
+package me.shedaniel.rei.impl.client.gui.widget;
+
+import me.shedaniel.rei.api.common.util.ImmutableTextComponent;
+import me.shedaniel.rei.impl.client.gui.error.ErrorsEntryListWidget;
+import me.shedaniel.rei.impl.client.gui.error.ErrorsScreen;
+import me.shedaniel.rei.impl.client.util.CrashReportUtils;
+import net.minecraft.CrashReport;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.resources.language.I18n;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.network.chat.TranslatableComponent;
+import net.minecraft.server.Bootstrap;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.function.Function;
+
+public class CatchingExceptionUtils {
+ public static void handleThrowable(Throwable throwable, String task) {
+ CrashReport report = CrashReportUtils.essential(throwable, task);
+ File reportsFolder = new File(Minecraft.getInstance().gameDirectory, "crash-reports");
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
+ File crashReportFile = new File(reportsFolder, "crash-" + format.format(new Date()) + "-client.txt");
+ report.saveToFile(crashReportFile);
+ Bootstrap.realStdoutPrintln(report.getFriendlyReport());
+ List<Object> components = new ArrayList<>();
+ components.add(new TextComponent(I18n.get("text.rei.crash.description", report.getTitle())));
+ components.add((Function<Integer, ErrorsEntryListWidget.Entry>) width -> new ErrorsEntryListWidget.LinkEntry(new TranslatableComponent("text.rei.crash.crash_report"), crashReportFile.toURI().toString(), width));
+ components.add(ImmutableTextComponent.EMPTY);
+ components.add(new TextComponent(report.getFriendlyReport().replace("\t", " ")));
+ Minecraft.getInstance().setScreen(new ErrorsScreen(new TranslatableComponent("text.rei.crash.title"), components));
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java
index e1d7a493f..bea5a7669 100644
--- a/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java
+++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/util/CrashReportUtils.java
@@ -24,6 +24,7 @@
package me.shedaniel.rei.impl.client.util;
import me.shedaniel.rei.api.client.gui.Renderer;
+import me.shedaniel.rei.impl.client.gui.widget.CatchingExceptionUtils;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
@@ -66,4 +67,8 @@ public class CrashReportUtils {
public static ReportedException throwReport(CrashReport report) {
return new ReportedException(report);
}
+
+ public static void catchReport(CrashReport report) {
+ CatchingExceptionUtils.handleThrowable(new ReportedException(report), report.getTitle());
+ }
}