From 03e8733ba0f95fc20672348eafec515e1362af0c Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 6 Nov 2021 11:25:48 +0100 Subject: [PATCH] Add UI that presents Fixer Errors to the User(paulevsGitch/BetterNether#436) --- .../ru/bclib/api/datafixer/DataFixerAPI.java | 69 ++++++++++++++++--- .../gui/screens/LevelFixErrorScreen.java | 60 ++++++++++++++++ .../ru/bclib/gui/screens/ModListScreen.java | 1 - .../ru/bclib/mixin/client/MinecraftMixin.java | 2 +- .../resources/assets/bclib/lang/de_de.json | 5 +- .../resources/assets/bclib/lang/en_us.json | 5 +- 6 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 src/main/java/ru/bclib/gui/screens/LevelFixErrorScreen.java diff --git a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java index 088a01ba..b58f0f5b 100644 --- a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java +++ b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java @@ -25,6 +25,7 @@ import ru.bclib.api.WorldDataAPI; import ru.bclib.config.Configs; import ru.bclib.gui.screens.AtomicProgressListener; import ru.bclib.gui.screens.ConfirmFixScreen; +import ru.bclib.gui.screens.LevelFixErrorScreen; import ru.bclib.gui.screens.ProgressScreen; import ru.bclib.util.Logger; @@ -47,6 +48,24 @@ public class DataFixerAPI { static final Logger LOGGER = new Logger("DataFixerAPI"); static class State { public boolean didFail = false; + protected ArrayList errors = new ArrayList<>(); + + public void addError(String s){ + errors.add(s); + } + + public boolean hasError(){ + return errors.size()>0; + } + + public String getErrorMessage(){ + return errors.stream().reduce("", (a, b) -> a + " - " + b + "\n"); + } + + public String[] getErrorMessages(){ + String[] res = new String[errors.size()]; + return errors.toArray(res); + } } @FunctionalInterface @@ -200,30 +219,51 @@ public class DataFixerAPI { progress = null; } - Runnable runner = () -> { + Supplier runner = () -> { if (createBackup) { progress.progressStage(new TranslatableComponent("message.bclib.datafixer.progress.waitbackup")); EditWorldScreen.makeBackupAndShowToast(Minecraft.getInstance().getLevelSource(), levelID); } if (applyFixes) { - runDataFixes(dir, profile, progress); + return runDataFixes(dir, profile, progress); } + + return new State(); }; if (showUI) { Thread fixerThread = new Thread(() -> { - runner.run(); - - Minecraft.getInstance().execute(() -> { - if (profile != null && showUI) { - onResume.accept(applyFixes); - } - }); + State state = runner.get(); + for (int i=0; i<20; i++) + state.addError("Hello World"); + + Minecraft.getInstance() + .execute(() -> { + if (profile != null && showUI) { + //something went wrong, show the user our error + if (state.didFail || state.hasError()){ + Minecraft.getInstance() + .setScreen(new LevelFixErrorScreen(Minecraft.getInstance().screen, state.getErrorMessages(), (markFixed)->{ + if (markFixed) { + profile.markApplied(); + } + onResume.accept(applyFixes); + })); + } else { + onResume.accept(applyFixes); + } + } + }); + }); fixerThread.start(); } else { - runner.run(); + State state = runner.get(); + if (state.hasError()){ + LOGGER.error("There were Errors while fixing the Level:"); + LOGGER.error(state.getErrorMessage()); + } } }; @@ -270,7 +310,7 @@ public class DataFixerAPI { Minecraft.getInstance().setScreen(new ConfirmFixScreen((Screen) null, whenFinished::accept)); } - private static void runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) { + private static State runDataFixes(File dir, MigrationProfile profile, AtomicProgressListener progress) { State state = new State(); progress.resetAtomic(); @@ -295,6 +335,7 @@ public class DataFixerAPI { profile.patchWorldData(); } catch (PatchDidiFailException e){ state.didFail = true; + state.addError("Failed fixing worldconfig (" + e.getMessage() + ")"); BCLib.LOGGER.error(e.getMessage()); } progress.incAtomic(maxProgress); @@ -313,6 +354,8 @@ public class DataFixerAPI { progress.incAtomic(maxProgress); progress.stop(); + + return state; } private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) { @@ -342,6 +385,7 @@ public class DataFixerAPI { } catch (Exception e) { BCLib.LOGGER.error("Failed fixing Level-Data."); + state.addError("Failed fixing Level-Data in level.dat (" + e.getMessage() + ")"); state.didFail = true; e.printStackTrace(); } @@ -361,6 +405,7 @@ public class DataFixerAPI { } catch (Exception e) { BCLib.LOGGER.error("Failed fixing Player-Data."); + state.addError("Failed fixing Player-Data in " + file.getName() + " (" + e.getMessage() + ")"); state.didFail = true; e.printStackTrace(); } @@ -448,6 +493,7 @@ public class DataFixerAPI { } catch (PatchDidiFailException e) { BCLib.LOGGER.error("Failed fixing BlockState in " + pos); + state.addError("Failed fixing BlockState in " + pos + " (" + e.getMessage() + ")"); state.didFail = true; changed[0] = false; e.printStackTrace(); @@ -468,6 +514,7 @@ public class DataFixerAPI { } catch (Exception e) { BCLib.LOGGER.error("Failed fixing Region."); + state.addError("Failed fixing Region in " + file.getName() + " (" + e.getMessage() + ")"); state.didFail = true; e.printStackTrace(); } diff --git a/src/main/java/ru/bclib/gui/screens/LevelFixErrorScreen.java b/src/main/java/ru/bclib/gui/screens/LevelFixErrorScreen.java new file mode 100644 index 00000000..1615c0f2 --- /dev/null +++ b/src/main/java/ru/bclib/gui/screens/LevelFixErrorScreen.java @@ -0,0 +1,60 @@ +package ru.bclib.gui.screens; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.TranslatableComponent; +import ru.bclib.gui.gridlayout.GridColumn; +import ru.bclib.gui.gridlayout.GridLayout; +import ru.bclib.gui.gridlayout.GridRow; + +@Environment(EnvType.CLIENT) +public class LevelFixErrorScreen extends BCLibScreen { + private final String[] errors; + final Listener onContinue; + + public LevelFixErrorScreen(Screen parent, String[] errors, Listener onContinue) { + super(parent, new TranslatableComponent("title.bclib.datafixer.error"), 10, true); + this.errors = errors; + this.onContinue = onContinue; + } + + @Override + protected void initLayout() { + grid.addSpacerRow(); + grid.addRow().addMessage(new TranslatableComponent("message.bclib.datafixer.error"), font, GridLayout.Alignment.CENTER); + grid.addSpacerRow(8); + + GridRow row = grid.addRow(); + row.addSpacer(10); + GridColumn col = row.addColumn(300, GridLayout.GridValueType.CONSTANT); + for (String error : errors){ + TextComponent dash = new TextComponent("-"); + row = col.addRow(); + row.addString(dash, this); + + row.addSpacer(4); + row.addString(new TextComponent(error), this); + } + + grid.addSpacerRow(8); + row = grid.addRow(); + row.addFiller(); + row.addButton(new TranslatableComponent("title.bclib.datafixer.error.continue"), 0.5f, 20, font, (n)-> { + onClose(); + onContinue.doContinue(true); + }); + row.addSpacer(); + row.addButton(CommonComponents.GUI_CANCEL, 20, font, (n)-> { + this.minecraft.setScreen(null); + }); + row.addFiller(); + } + + @Environment(EnvType.CLIENT) + public interface Listener { + void doContinue(boolean markFixed); + } +} diff --git a/src/main/java/ru/bclib/gui/screens/ModListScreen.java b/src/main/java/ru/bclib/gui/screens/ModListScreen.java index 74ee4a33..2a54264b 100644 --- a/src/main/java/ru/bclib/gui/screens/ModListScreen.java +++ b/src/main/java/ru/bclib/gui/screens/ModListScreen.java @@ -208,7 +208,6 @@ public class ModListScreen extends BCLibScreen { row.addFiller(); row.addButton(buttonTitle, 20, font, (n)-> { onClose(); - System.out.println("Closing"); }); row.addFiller(); } diff --git a/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java b/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java index 76d00a4d..f1cb2523 100644 --- a/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java +++ b/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java @@ -61,7 +61,7 @@ public abstract class MinecraftMixin { DataExchangeAPI.prepareServerside(); if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> { - this.doLoadLevel(levelID, RegistryAccess.builtin(), Minecraft::loadDataPacks, Minecraft::loadWorldData, false, Minecraft.ExperimentalDialogType.BACKUP); + this.doLoadLevel(levelID, RegistryAccess.builtin(), Minecraft::loadDataPacks, Minecraft::loadWorldData, false, appliedFixes?ExperimentalDialogType.NONE:ExperimentalDialogType.BACKUP); })) { ci.cancel(); } diff --git a/src/main/resources/assets/bclib/lang/de_de.json b/src/main/resources/assets/bclib/lang/de_de.json index c9b2518e..7fcb0c99 100644 --- a/src/main/resources/assets/bclib/lang/de_de.json +++ b/src/main/resources/assets/bclib/lang/de_de.json @@ -43,5 +43,8 @@ "message.bclib.datafixer.progress.regions": "Alle Regionen reparieren", "message.bclib.datafixer.progress.saving": "Patch-Status speichern", "title.bclib.datafixer.progress": "Welt in Ordnung bringen", - "message.bclib.datafixer.progress": "Anwenden aller Änderungen" + "message.bclib.datafixer.progress": "Anwenden aller Änderungen", + "title.bclib.datafixer.error": "Fehler beim Reparieren der Welt", + "message.bclib.datafixer.error": "Es gab Fehler beim Reparieren der Welt. Das bedeutet, dass dieser Level wahrscheinlich in einem inkonsistenten Zustand ist und Sie ihn nicht spielen sollten. Bitte stellen Sie Ihr Backup wieder her und beheben Sie die unten aufgeführten Fehler, bevor Sie es erneut versuchen.", + "title.bclib.datafixer.error.continue": "Continue and Mark as Fixed" } \ No newline at end of file diff --git a/src/main/resources/assets/bclib/lang/en_us.json b/src/main/resources/assets/bclib/lang/en_us.json index 3ef32c1e..68aa85bc 100644 --- a/src/main/resources/assets/bclib/lang/en_us.json +++ b/src/main/resources/assets/bclib/lang/en_us.json @@ -43,5 +43,8 @@ "message.bclib.datafixer.progress.regions": "Repairing all Regions", "message.bclib.datafixer.progress.saving": "Saving Patch State", "title.bclib.datafixer.progress": "Fixing World", - "message.bclib.datafixer.progress": "Applying all Patches to your World." + "message.bclib.datafixer.progress": "Applying all Patches to your World.", + "title.bclib.datafixer.error": "Errors while fixing World", + "message.bclib.datafixer.error": "There were errors while repairing the world. This means that this level is probably in an inconsistent state and you should not play it. Please restore your backup and fix the errors below before trying again.", + "title.bclib.datafixer.error.continue": "Fortfahren und als behoben markieren" } \ No newline at end of file