diff --git a/client/src/main/java/org/geysermc/rainbow/client/RainbowClient.java b/client/src/main/java/org/geysermc/rainbow/client/RainbowClient.java index 1ef7cea..131846b 100644 --- a/client/src/main/java/org/geysermc/rainbow/client/RainbowClient.java +++ b/client/src/main/java/org/geysermc/rainbow/client/RainbowClient.java @@ -6,6 +6,7 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; import net.minecraft.commands.synchronization.SingletonArgumentInfo; import org.geysermc.rainbow.Rainbow; +import org.geysermc.rainbow.RainbowIO; import org.geysermc.rainbow.client.command.CommandSuggestionsArgumentType; import org.geysermc.rainbow.client.command.PackGeneratorCommand; import org.geysermc.rainbow.client.mapper.PackMapper; @@ -23,5 +24,7 @@ public class RainbowClient implements ClientModInitializer { ArgumentTypeRegistry.registerArgumentType(Rainbow.getModdedLocation("command_suggestions"), CommandSuggestionsArgumentType.class, SingletonArgumentInfo.contextFree(CommandSuggestionsArgumentType::new)); + + RainbowIO.registerExceptionListener(new RainbowClientIOHandler()); } } diff --git a/client/src/main/java/org/geysermc/rainbow/client/RainbowClientIOHandler.java b/client/src/main/java/org/geysermc/rainbow/client/RainbowClientIOHandler.java new file mode 100644 index 0000000..f31f1f8 --- /dev/null +++ b/client/src/main/java/org/geysermc/rainbow/client/RainbowClientIOHandler.java @@ -0,0 +1,18 @@ +package org.geysermc.rainbow.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.toasts.SystemToast; +import net.minecraft.network.chat.Component; +import org.geysermc.rainbow.RainbowIO; + +import java.io.IOException; + +public class RainbowClientIOHandler implements RainbowIO.IOExceptionListener { + private static final SystemToast.SystemToastId TOAST_ID = new SystemToast.SystemToastId(); + + @Override + public void error(IOException exception) { + Minecraft.getInstance().getToastManager().addToast(new SystemToast(TOAST_ID, + Component.translatable("toast.rainbow.io_exception.title"), Component.translatable("toast.rainbow.io_exception.description"))); + } +} diff --git a/client/src/main/resources/assets/rainbow/lang/en_us.json b/client/src/main/resources/assets/rainbow/lang/en_us.json index 7fe4de1..cc89808 100644 --- a/client/src/main/resources/assets/rainbow/lang/en_us.json +++ b/client/src/main/resources/assets/rainbow/lang/en_us.json @@ -13,5 +13,7 @@ "commands.rainbow.pack_created": "Created pack with name %s", "commands.rainbow.pack_finished_error": "Errors occurred whilst writing the pack to disk!", "commands.rainbow.pack_finished_successfully": "Wrote pack to disk", - "commands.rainbow.stopped_automatic_mapping": "Stopped automatic mapping of custom items" + "commands.rainbow.stopped_automatic_mapping": "Stopped automatic mapping of custom items", + "toast.rainbow.io_exception.description": "Please check your game logs for more information", + "toast.rainbow.io_exception.title": "A filesystem error occurred in Rainbow!" } \ No newline at end of file diff --git a/rainbow/src/main/java/org/geysermc/rainbow/RainbowIO.java b/rainbow/src/main/java/org/geysermc/rainbow/RainbowIO.java index e2f7cbe..5068ef6 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/RainbowIO.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/RainbowIO.java @@ -4,37 +4,39 @@ import com.mojang.logging.LogUtils; import org.slf4j.Logger; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; public final class RainbowIO { private static final Logger LOGGER = LogUtils.getLogger(); + private static final List listeners = new ArrayList<>(); private RainbowIO() {} - public static T safeIO(IOSupplier supplier, T defaultValue) { - try { - return supplier.get(); - } catch (IOException exception) { - LOGGER.error("Failed to perform IO operation!", exception); - return defaultValue; - } - } - public static Optional safeIO(IOSupplier supplier) { try { return Optional.ofNullable(supplier.get()); } catch (IOException exception) { LOGGER.error("Failed to perform IO operation!", exception); + listeners.forEach(listener -> listener.error(exception)); return Optional.empty(); } } + public static T safeIO(IOSupplier supplier, T defaultValue) { + return safeIO(supplier).orElse(defaultValue); + } + public static void safeIO(IORunnable runnable) { - try { + safeIO(() -> { runnable.run(); - } catch (IOException exception) { - LOGGER.error("Failed to perform IO operation!", exception); - } + return null; + }); + } + + public static void registerExceptionListener(IOExceptionListener listener) { + listeners.add(listener); } @FunctionalInterface @@ -48,4 +50,10 @@ public final class RainbowIO { void run() throws IOException; } + + @FunctionalInterface + public interface IOExceptionListener { + + void error(IOException exception); + } }