From d41a4605894f82243e58073ebd0f91f274bc430e Mon Sep 17 00:00:00 2001 From: FalsePattern <30945458+FalsePattern@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:26:25 +0200 Subject: [PATCH] TOASTED. R O A S T E D. --- .../lib/internal/FalsePatternLib.java | 8 +- .../internal/{ => config}/LibraryConfig.java | 17 +- .../{ => config}/LibraryGuiConfig.java | 6 +- .../{ => config}/LibraryGuiFactory.java | 2 +- .../lib/internal/config/ToastConfig.java | 55 ++++++ .../dependencies/DependencyLoaderImpl.java | 2 +- .../lib/internal/impl/toast/GuiToastImpl.java | 186 ++++++++++++++++++ .../lib/internal/proxy/ClientProxy.java | 21 +- .../lib/internal/proxy/CommonProxy.java | 9 +- .../com/falsepattern/lib/toasts/GuiToast.java | 49 +++++ .../com/falsepattern/lib/toasts/IToast.java | 70 +++++++ .../falsepattern/lib/toasts/SimpleToast.java | 126 ++++++++++++ .../falsepattern/lib/toasts/icon/ToastBG.java | 70 +++++++ .../lib/toasts/icon/ToastIcon.java | 52 +++++ .../lib/toasts/icon/ToastTexture.java | 55 ++++++ .../lib/updates/UpdateChecker.java | 2 +- .../com/falsepattern/lib/util/RenderUtil.java | 60 +++++- .../assets/falsepatternlib/lang/en_US.lang | 6 + .../assets/falsepatternlib/sounds.json | 14 ++ .../falsepatternlib/sounds/toast/in.ogg | Bin 0 -> 20040 bytes .../falsepatternlib/sounds/toast/out.ogg | Bin 0 -> 19939 bytes .../textures/gui/toast_dark.png | Bin 0 -> 587 bytes .../textures/gui/toast_dark_rounded.png | Bin 0 -> 611 bytes .../textures/gui/toast_narrator.png | Bin 0 -> 661 bytes .../textures/gui/toast_narrator_rounded.png | Bin 0 -> 690 bytes .../textures/gui/toast_white.png | Bin 0 -> 587 bytes .../textures/gui/toast_white_rounded.png | Bin 0 -> 611 bytes 27 files changed, 787 insertions(+), 23 deletions(-) rename src/main/java/com/falsepattern/lib/internal/{ => config}/LibraryConfig.java (67%) rename src/main/java/com/falsepattern/lib/internal/{ => config}/LibraryGuiConfig.java (86%) rename src/main/java/com/falsepattern/lib/internal/{ => config}/LibraryGuiFactory.java (96%) create mode 100644 src/main/java/com/falsepattern/lib/internal/config/ToastConfig.java create mode 100644 src/main/java/com/falsepattern/lib/internal/impl/toast/GuiToastImpl.java create mode 100644 src/main/java/com/falsepattern/lib/toasts/GuiToast.java create mode 100644 src/main/java/com/falsepattern/lib/toasts/IToast.java create mode 100644 src/main/java/com/falsepattern/lib/toasts/SimpleToast.java create mode 100644 src/main/java/com/falsepattern/lib/toasts/icon/ToastBG.java create mode 100644 src/main/java/com/falsepattern/lib/toasts/icon/ToastIcon.java create mode 100644 src/main/java/com/falsepattern/lib/toasts/icon/ToastTexture.java create mode 100644 src/main/resources/assets/falsepatternlib/sounds.json create mode 100644 src/main/resources/assets/falsepatternlib/sounds/toast/in.ogg create mode 100644 src/main/resources/assets/falsepatternlib/sounds/toast/out.ogg create mode 100644 src/main/resources/assets/falsepatternlib/textures/gui/toast_dark.png create mode 100644 src/main/resources/assets/falsepatternlib/textures/gui/toast_dark_rounded.png create mode 100644 src/main/resources/assets/falsepatternlib/textures/gui/toast_narrator.png create mode 100644 src/main/resources/assets/falsepatternlib/textures/gui/toast_narrator_rounded.png create mode 100644 src/main/resources/assets/falsepatternlib/textures/gui/toast_white.png create mode 100644 src/main/resources/assets/falsepatternlib/textures/gui/toast_white_rounded.png diff --git a/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java b/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java index b5b8bf9..8b990d4 100644 --- a/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java +++ b/src/main/java/com/falsepattern/lib/internal/FalsePatternLib.java @@ -23,6 +23,7 @@ package com.falsepattern.lib.internal; import com.falsepattern.lib.internal.proxy.CommonProxy; import cpw.mods.fml.common.*; +import cpw.mods.fml.common.event.FMLConstructionEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; @@ -41,7 +42,7 @@ import org.apache.logging.log4j.Logger; name = Tags.MODNAME, version = Tags.VERSION, acceptedMinecraftVersions = "[1.7.10]", - guiFactory = Tags.GROUPNAME + ".internal.LibraryGuiFactory", + guiFactory = Tags.GROUPNAME + ".internal.config.LibraryGuiFactory", acceptableRemoteVersions = "*") public class FalsePatternLib { public static final String UPDATE_URL = "https://falsepattern.com/mc/versions.json"; @@ -58,6 +59,11 @@ public class FalsePatternLib { log.info("Version " + Tags.VERSION + " initialized!"); } + @Mod.EventHandler + public void construct(FMLConstructionEvent e) { + proxy.construct(e); + } + @Mod.EventHandler public void preInit(FMLPreInitializationEvent e) { proxy.preInit(e); diff --git a/src/main/java/com/falsepattern/lib/internal/LibraryConfig.java b/src/main/java/com/falsepattern/lib/internal/config/LibraryConfig.java similarity index 67% rename from src/main/java/com/falsepattern/lib/internal/LibraryConfig.java rename to src/main/java/com/falsepattern/lib/internal/config/LibraryConfig.java index 1e18a00..e648872 100644 --- a/src/main/java/com/falsepattern/lib/internal/LibraryConfig.java +++ b/src/main/java/com/falsepattern/lib/internal/config/LibraryConfig.java @@ -18,21 +18,24 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package com.falsepattern.lib.internal; +package com.falsepattern.lib.internal.config; import com.falsepattern.lib.config.Config; +import com.falsepattern.lib.internal.Tags; @Config(modid = Tags.MODID) public class LibraryConfig { @Config.Comment({"Used to control whether FalsePatternLib should check for outdated mods.", - "If you're building a public modpack, you should turn this off so that your users don't " + - "get nagged about outdated mods."}) + "If you're building a public modpack, you should turn this off so that your users don't " + + "get nagged about outdated mods."}) @Config.LangKey("config.falsepatternlib.updatecheck") - public static boolean ENABLE_UPDATE_CHECKER = true; + @Config.DefaultBoolean(true) + public static boolean ENABLE_UPDATE_CHECKER; @Config.Comment({"Used to control whether FalsePatternLib should be allowed to use the internet.", - "If this is disabled, library downloads will be blocked.", - "Note that if a mod tries to download a library that is not downloaded yet, the game will crash."}) + "If this is disabled, library downloads will be blocked.", + "Note that if a mod tries to download a library that is not downloaded yet, the game will crash."}) @Config.LangKey("config.falsepatternlib.disableinternet") - public static boolean ENABLE_LIBRARY_DOWNLOADS = true; + @Config.DefaultBoolean(true) + public static boolean ENABLE_LIBRARY_DOWNLOADS; } diff --git a/src/main/java/com/falsepattern/lib/internal/LibraryGuiConfig.java b/src/main/java/com/falsepattern/lib/internal/config/LibraryGuiConfig.java similarity index 86% rename from src/main/java/com/falsepattern/lib/internal/LibraryGuiConfig.java rename to src/main/java/com/falsepattern/lib/internal/config/LibraryGuiConfig.java index 3a292af..5d0ad96 100644 --- a/src/main/java/com/falsepattern/lib/internal/LibraryGuiConfig.java +++ b/src/main/java/com/falsepattern/lib/internal/config/LibraryGuiConfig.java @@ -18,10 +18,12 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package com.falsepattern.lib.internal; +package com.falsepattern.lib.internal.config; import com.falsepattern.lib.config.ConfigException; import com.falsepattern.lib.config.SimpleGuiConfig; +import com.falsepattern.lib.internal.Tags; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.gui.GuiScreen; @@ -29,6 +31,6 @@ import net.minecraft.client.gui.GuiScreen; @SideOnly(Side.CLIENT) public class LibraryGuiConfig extends SimpleGuiConfig { public LibraryGuiConfig(GuiScreen parent) throws ConfigException { - super(parent, LibraryConfig.class, Tags.MODID, Tags.MODNAME); + super(parent, new Class[]{LibraryConfig.class, ToastConfig.class}, Tags.MODID, Tags.MODNAME); } } diff --git a/src/main/java/com/falsepattern/lib/internal/LibraryGuiFactory.java b/src/main/java/com/falsepattern/lib/internal/config/LibraryGuiFactory.java similarity index 96% rename from src/main/java/com/falsepattern/lib/internal/LibraryGuiFactory.java rename to src/main/java/com/falsepattern/lib/internal/config/LibraryGuiFactory.java index 3bfc131..cbb33e0 100644 --- a/src/main/java/com/falsepattern/lib/internal/LibraryGuiFactory.java +++ b/src/main/java/com/falsepattern/lib/internal/config/LibraryGuiFactory.java @@ -18,7 +18,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package com.falsepattern.lib.internal; +package com.falsepattern.lib.internal.config; import com.falsepattern.lib.config.SimpleGuiFactory; import cpw.mods.fml.relauncher.Side; diff --git a/src/main/java/com/falsepattern/lib/internal/config/ToastConfig.java b/src/main/java/com/falsepattern/lib/internal/config/ToastConfig.java new file mode 100644 index 0000000..a32e8ac --- /dev/null +++ b/src/main/java/com/falsepattern/lib/internal/config/ToastConfig.java @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + * + * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + * + * This program 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. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.internal.config; + +import com.falsepattern.lib.config.Config; +import com.falsepattern.lib.internal.Tags; + +@Config(modid = Tags.MODID, + category = "toasts") +public class ToastConfig { + @Config.Comment("The maximum amount of toasts to show on the screen") + @Config.LangKey("config.falsepatternlib.maxtoasts") + @Config.DefaultInt(5) + @Config.RangeInt(min = 1, + max = 10) + public static int MAX_VISIBLE; + + @Config.Comment("The amount of empty space from the top of the screen in pixels") + @Config.LangKey("config.falsepatternlib.toastoffset") + @Config.DefaultInt(0) + @Config.RangeInt(min = 0, + max = 10000) + public static int Y_OFFSET; + + @Config.Comment("Which side of the screen should toasts show up on") + @Config.LangKey("config.falsepatternlib.toastalign") + @Config.DefaultEnum("Right") + public static Side ALIGN; + + public static boolean leftAlign() { + return ALIGN == Side.Left; + } + + public enum Side { + Left, Right + } +} diff --git a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java index c7ca12f..b670921 100644 --- a/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java +++ b/src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java @@ -24,7 +24,7 @@ import com.falsepattern.lib.dependencies.DependencyLoader; import com.falsepattern.lib.dependencies.Version; import com.falsepattern.lib.internal.FalsePatternLib; import com.falsepattern.lib.internal.Internet; -import com.falsepattern.lib.internal.LibraryConfig; +import com.falsepattern.lib.internal.config.LibraryConfig; import com.falsepattern.lib.internal.Tags; import com.falsepattern.lib.util.FileUtil; import lombok.NonNull; diff --git a/src/main/java/com/falsepattern/lib/internal/impl/toast/GuiToastImpl.java b/src/main/java/com/falsepattern/lib/internal/impl/toast/GuiToastImpl.java new file mode 100644 index 0000000..4040e9b --- /dev/null +++ b/src/main/java/com/falsepattern/lib/internal/impl/toast/GuiToastImpl.java @@ -0,0 +1,186 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.internal.impl.toast; + +import com.falsepattern.lib.internal.config.LibraryConfig; +import com.falsepattern.lib.internal.config.ToastConfig; +import com.falsepattern.lib.toasts.IToast; +import com.falsepattern.lib.util.MathUtil; +import com.google.common.collect.Queues; +import lombok.val; +import lombok.var; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.RenderHelper; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Deque; + +@SideOnly(Side.CLIENT) +public class GuiToastImpl extends Gui { + private final Minecraft mc; + private final Deque toastsQueue = Queues.newArrayDeque(); + private ToastInstance[] visible = new ToastInstance[0]; + private static GuiToastImpl instance; + + public static void initialize(Minecraft mc) { + if (instance != null) { + return; + } + instance = new GuiToastImpl(mc); + FMLCommonHandler.instance().bus().register(instance); + } + + public static GuiToastImpl getInstance() { + return instance; + } + + @SubscribeEvent + public void updateToasts(TickEvent.RenderTickEvent event) { + if ( event.phase != TickEvent.Phase.END) { + return; + } + mc.mcProfiler.startSection("toasts"); + drawToast(new ScaledResolution(mc, mc.displayWidth, mc.displayHeight)); + mc.mcProfiler.endSection(); + } + + + public GuiToastImpl(Minecraft mcIn) { + this.mc = mcIn; + } + + public void drawToast(ScaledResolution resolution) { + if (!this.mc.gameSettings.hideGUI) { + RenderHelper.disableStandardItemLighting(); + if (ToastConfig.MAX_VISIBLE != visible.length) { + visible = Arrays.copyOf(visible, ToastConfig.MAX_VISIBLE); + } + + for (int i = 0; i < this.visible.length; ++i) { + val toast = this.visible[i]; + + if (toast != null && toast.render(ToastConfig.leftAlign() ? 0 : resolution.getScaledWidth(), i)) { + this.visible[i] = null; + } + + if (this.visible[i] == null && !this.toastsQueue.isEmpty()) { + this.visible[i] = new ToastInstance<>(this.toastsQueue.removeFirst()); + } + } + } + } + + @Nullable + public T getToast(Class toastClass, Object type) { + for (val toast : this.visible) { + if (toast != null && toastClass.isAssignableFrom(toast.getToast().getClass()) && + toast.getToast().getType().equals(type)) { + return toastClass.cast(toast); + } + } + + for (val toast : this.toastsQueue) { + if (toastClass.isAssignableFrom(toast.getClass()) && toast.getType().equals(type)) { + return toastClass.cast(toast); + } + } + + return null; + } + + public void clear() { + Arrays.fill(this.visible, null); + this.toastsQueue.clear(); + } + + public void add(IToast toastIn) { + this.toastsQueue.add(toastIn); + } + + public Minecraft getMinecraft() { + return this.mc; + } + + @SideOnly(Side.CLIENT) + class ToastInstance { + private final T toast; + private long animationTime; + private long visibleTime; + private IToast.Visibility visibility; + + private ToastInstance(T toastIn) { + this.animationTime = -1L; + this.visibleTime = -1L; + this.visibility = IToast.Visibility.SHOW; + this.toast = toastIn; + } + + public T getToast() { + return this.toast; + } + + private float getVisibility(long currentTime) { + var visibility = MathUtil.clamp((float) (currentTime - this.animationTime) / 600.0F, 0.0F, 1.0F); + visibility = visibility * visibility; + return this.visibility == IToast.Visibility.HIDE ? 1.0F - visibility : visibility; + } + + public boolean render(int x, int y) { + val sysTime = Minecraft.getSystemTime(); + + if (this.animationTime == -1L) { + this.animationTime = sysTime; + this.visibility.playSound(GuiToastImpl.this.mc.getSoundHandler()); + } + + if (this.visibility == IToast.Visibility.SHOW && sysTime - this.animationTime <= 600L) { + this.visibleTime = sysTime; + } + + GL11.glPushMatrix(); + val shift = toast.width() * getVisibility(sysTime); + val X = ToastConfig.leftAlign() ? shift - toast.width() : x - shift; + GL11.glTranslatef(X, + (float) (y * 32) + ToastConfig.Y_OFFSET, + (float) (500 + y)); + val visibility = this.toast.draw(GuiToastImpl.this, sysTime - this.visibleTime); + GL11.glPopMatrix(); + + if (visibility != this.visibility) { + this.animationTime = sysTime - (long) ((int) ((1.0F - this.getVisibility(sysTime)) * 600.0F)); + this.visibility = visibility; + this.visibility.playSound(GuiToastImpl.this.mc.getSoundHandler()); + } + + return this.visibility == IToast.Visibility.HIDE && sysTime - this.animationTime > 600L; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/falsepattern/lib/internal/proxy/ClientProxy.java b/src/main/java/com/falsepattern/lib/internal/proxy/ClientProxy.java index baedda4..cd1ab8b 100644 --- a/src/main/java/com/falsepattern/lib/internal/proxy/ClientProxy.java +++ b/src/main/java/com/falsepattern/lib/internal/proxy/ClientProxy.java @@ -22,18 +22,21 @@ package com.falsepattern.lib.internal.proxy; import com.falsepattern.lib.internal.FalsePatternLib; import com.falsepattern.lib.internal.Tags; +import com.falsepattern.lib.internal.impl.toast.GuiToastImpl; import com.falsepattern.lib.updates.UpdateChecker; -import cpw.mods.fml.client.IModGuiFactory; +import lombok.val; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.util.IChatComponent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import cpw.mods.fml.common.event.FMLConstructionEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -import lombok.val; -import net.minecraft.client.entity.EntityPlayerSP; -import net.minecraft.util.IChatComponent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.EntityJoinWorldEvent; import java.util.Collections; import java.util.List; @@ -43,6 +46,12 @@ import java.util.concurrent.CompletableFuture; public class ClientProxy extends CommonProxy { private CompletableFuture> chatFuture; + @Override + public void construct(FMLConstructionEvent e) { + super.construct(e); + GuiToastImpl.initialize(Minecraft.getMinecraft()); + } + @Override public void preInit(FMLPreInitializationEvent e) { super.preInit(e); diff --git a/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java b/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java index 50ad1b0..a6f4795 100644 --- a/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java +++ b/src/main/java/com/falsepattern/lib/internal/proxy/CommonProxy.java @@ -23,10 +23,13 @@ package com.falsepattern.lib.internal.proxy; import com.falsepattern.lib.config.ConfigException; import com.falsepattern.lib.config.ConfigurationManager; import com.falsepattern.lib.internal.FalsePatternLib; -import com.falsepattern.lib.internal.LibraryConfig; +import com.falsepattern.lib.internal.config.LibraryConfig; +import com.falsepattern.lib.internal.config.ToastConfig; import com.falsepattern.lib.internal.impl.config.ConfigurationManagerImpl; import com.falsepattern.lib.updates.ModUpdateInfo; import com.falsepattern.lib.updates.UpdateChecker; + +import cpw.mods.fml.common.event.FMLConstructionEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import lombok.val; @@ -39,10 +42,14 @@ public class CommonProxy { protected CompletableFuture> updatesFuture; + public void construct(FMLConstructionEvent e) { + } + public void preInit(FMLPreInitializationEvent e) { ConfigurationManagerImpl.registerBus(); try { ConfigurationManager.registerConfig(LibraryConfig.class); + ConfigurationManager.registerConfig(ToastConfig.class); } catch (ConfigException ex) { FalsePatternLib.getLog().error("Failed to register config!", ex); } diff --git a/src/main/java/com/falsepattern/lib/toasts/GuiToast.java b/src/main/java/com/falsepattern/lib/toasts/GuiToast.java new file mode 100644 index 0000000..9f15bb8 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/toasts/GuiToast.java @@ -0,0 +1,49 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.toasts; + +import com.falsepattern.lib.StableAPI; +import com.falsepattern.lib.internal.impl.toast.GuiToastImpl; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; + +@SideOnly(Side.CLIENT) +@StableAPI(since = "0.10.0") +public class GuiToast { + @StableAPI(since = "0.10.0") + @Nullable + public static T getToast(Class toastClass, Object type) { + return GuiToastImpl.getInstance().getToast(toastClass, type); + } + + @StableAPI(since = "0.10.0") + public static void clear() { + GuiToastImpl.getInstance().clear(); + } + + @StableAPI(since = "0.10.0") + public static void add(IToast toastIn) { + GuiToastImpl.getInstance().add(toastIn); + } +} diff --git a/src/main/java/com/falsepattern/lib/toasts/IToast.java b/src/main/java/com/falsepattern/lib/toasts/IToast.java new file mode 100644 index 0000000..c0b5309 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/toasts/IToast.java @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.toasts; + +import com.falsepattern.lib.StableAPI; +import com.falsepattern.lib.internal.Tags; +import com.falsepattern.lib.internal.impl.toast.GuiToastImpl; + +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.audio.SoundHandler; +import net.minecraft.util.ResourceLocation; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +@StableAPI(since = "0.10.0") +public interface IToast { + @StableAPI(since = "0.10.0") + Object NO_TOKEN = new Object(); + + @StableAPI(since = "0.10.0") + Visibility draw(GuiToastImpl toastGui, long delta); + + @StableAPI(since = "0.10.0") + int width(); + + @StableAPI(since = "0.10.0") + int height(); + + @StableAPI(since = "0.10.0") + default Object getType() { + return NO_TOKEN; + } + + @StableAPI(since = "0.10.0") + @SideOnly(Side.CLIENT) + enum Visibility { + SHOW(new ResourceLocation(Tags.MODID, "ui.toast.in")), + HIDE(new ResourceLocation(Tags.MODID, "ui.toast.out")); + + private final ResourceLocation sound; + + Visibility(ResourceLocation soundIn) { + this.sound = soundIn; + } + + @StableAPI(since = "0.10.0") + public void playSound(SoundHandler handler) { + handler.playSound(PositionedSoundRecord.func_147674_a(this.sound, 1.0F)); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/falsepattern/lib/toasts/SimpleToast.java b/src/main/java/com/falsepattern/lib/toasts/SimpleToast.java new file mode 100644 index 0000000..f06865e --- /dev/null +++ b/src/main/java/com/falsepattern/lib/toasts/SimpleToast.java @@ -0,0 +1,126 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.toasts; + +import com.falsepattern.lib.StableAPI; +import com.falsepattern.lib.internal.impl.toast.GuiToastImpl; +import com.falsepattern.lib.toasts.icon.ToastBG; +import com.falsepattern.lib.toasts.icon.ToastIcon; +import com.falsepattern.lib.util.MathUtil; +import lombok.NonNull; +import lombok.val; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.gui.Gui; +import net.minecraft.util.IChatComponent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import javax.annotation.Nullable; + +@SideOnly(Side.CLIENT) +@StableAPI(since = "0.10.0") +public class SimpleToast implements IToast { + private final ToastBG background; + private final ToastIcon icon; + private final String title; + private final String subtitle; + private final boolean hasProgressBar; + private final long timeout; + private IToast.Visibility visibility = IToast.Visibility.SHOW; + private long lastDelta; + private float displayedProgress; + private float currentProgress; + + @StableAPI(since = "0.10.0") + public SimpleToast(@NonNull ToastBG background, @Nullable ToastIcon icon, + IChatComponent titleComponent, @Nullable IChatComponent subtitleComponent, + boolean drawProgressBar, long timeout) { + this.background = background; + this.icon = icon; + this.title = titleComponent.getFormattedText(); + this.subtitle = subtitleComponent == null ? null : subtitleComponent.getFormattedText(); + this.hasProgressBar = drawProgressBar; + this.timeout = timeout; + } + + @Override + public IToast.Visibility draw(GuiToastImpl toastGui, long delta) { + GL11.glColor3f(1, 1, 1); + background.draw(toastGui, 0, 0); + if (icon != null) { + icon.draw(toastGui, 6, 6); + } + + val x = icon == null ? 5 : 5 + icon.getIcon().getIconWidth(); + val bgHeight = background.getIcon().getIconHeight(); + val fontRenderer = toastGui.getMinecraft().fontRenderer; + if (subtitle == null) { + fontRenderer.drawString(title, x, bgHeight / 2 - 5, 0xFFFFFFFF); + } else { + fontRenderer.drawString(title, x, 7, 0xFFFFFFFF); + fontRenderer.drawString(subtitle, x, bgHeight - 14, 0xFFFFFFFF); + } + + if (hasProgressBar) { + val bgWidth = background.getIcon().getIconWidth(); + Gui.drawRect(3, bgHeight - 4, bgWidth - 3, bgHeight - 3, 0xFFFFFFFF); + float f = (float) MathUtil.clampedLerp(displayedProgress, currentProgress, (float) (delta - lastDelta) / 100.0F); + int i; + + if (currentProgress >= displayedProgress) { + i = 0xff005500; + } else { + i = 0xff550000; + } + val barLength = bgWidth - 6; + Gui.drawRect(3, bgHeight - 4, (int) (3.0F + barLength * f), bgHeight - 3, i); + displayedProgress = f; + lastDelta = delta; + } + if (timeout > 0) { + if (delta >= timeout) { + hide(); + } + } + return visibility; + } + + @Override + public int width() { + return background.getIcon().getIconWidth(); + } + + @Override + public int height() { + return background.getIcon().getIconHeight(); + } + + @StableAPI(since = "0.10.0") + public void hide() { + visibility = IToast.Visibility.HIDE; + } + + @StableAPI(since = "0.10.0") + public void setProgress(float progress) { + this.currentProgress = progress; + } +} \ No newline at end of file diff --git a/src/main/java/com/falsepattern/lib/toasts/icon/ToastBG.java b/src/main/java/com/falsepattern/lib/toasts/icon/ToastBG.java new file mode 100644 index 0000000..b7ffbce --- /dev/null +++ b/src/main/java/com/falsepattern/lib/toasts/icon/ToastBG.java @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.toasts.icon; + +import com.falsepattern.lib.StableAPI; +import com.falsepattern.lib.internal.Tags; +import lombok.NonNull; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +@StableAPI(since = "0.10.0") +public class ToastBG extends ToastTexture { + @StableAPI(since = "0.10.0") + public static final ToastBG TOAST_DARK = new ToastBG(new ResourceLocation(Tags.MODID, "textures/gui/toast_dark.png"), 160, 32, 0xFFFFFFFF); + @StableAPI(since = "0.10.0") + public static final ToastBG TOAST_DARK_ROUNDED = new ToastBG(new ResourceLocation(Tags.MODID, "textures/gui/toast_dark_rounded.png"), 160, 32, 0xFFFFFFFF); + @StableAPI(since = "0.10.0") + public static final ToastBG TOAST_NARRATOR = new ToastBG(new ResourceLocation(Tags.MODID, "textures/gui/toast_narrator.png"), 160, 32, 0xFFAAAA00); + @StableAPI(since = "0.10.0") + public static final ToastBG TOAST_NARRATOR_ROUNDED = new ToastBG(new ResourceLocation(Tags.MODID, "textures/gui/toast_narrator_rounded.png"), 160, 32, 0xFFAAAA00); + @StableAPI(since = "0.10.0") + public static final ToastBG TOAST_WHITE = new ToastBG(new ResourceLocation(Tags.MODID, "textures/gui/toast_white.png"), 160, 32, 0xFF500050); + @StableAPI(since = "0.10.0") + public static final ToastBG TOAST_WHITE_ROUNDED = new ToastBG(new ResourceLocation(Tags.MODID, "textures/gui/toast_white_rounded.png"), 160, 32, 0xFF500050); + + @StableAPI(since = "0.10.0") + public final int defaultTextColor; + + @StableAPI(since = "0.10.0") + public ToastBG(@NonNull ResourceLocation texture, int width, int height, int defaultTextColor) { + super(texture, width, height); + this.defaultTextColor = defaultTextColor; + } + + @StableAPI(since = "0.10.0") + public ToastBG(@NonNull ResourceLocation texture, @NonNull IIcon icon, int defaultTextColor) { + super(texture, icon); + this.defaultTextColor = defaultTextColor; + } + + @Override + public void draw(Gui guiIn, int x, int y) { + GL11.glPushAttrib(GL11.GL_TEXTURE_BIT); + Minecraft.getMinecraft().getTextureManager().bindTexture(texture); + guiIn.drawTexturedModelRectFromIcon(x, y, icon, icon.getIconWidth(), icon.getIconHeight()); + GL11.glPopAttrib(); + } +} \ No newline at end of file diff --git a/src/main/java/com/falsepattern/lib/toasts/icon/ToastIcon.java b/src/main/java/com/falsepattern/lib/toasts/icon/ToastIcon.java new file mode 100644 index 0000000..5b78893 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/toasts/icon/ToastIcon.java @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.toasts.icon; + +import com.falsepattern.lib.StableAPI; +import lombok.NonNull; +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +@StableAPI(since = "0.10.0") +public class ToastIcon extends ToastTexture { + @StableAPI(since = "0.10.0") + public ToastIcon(@NonNull ResourceLocation texture, int width, int height) { + super(texture, width, height); + } + + @StableAPI(since = "0.10.0") + public ToastIcon(@NonNull ResourceLocation texture, @NonNull IIcon icon) { + super(texture, icon); + } + + @Override + public void draw(Gui guiIn, int x, int y) { + GL11.glPushAttrib(GL11.GL_TEXTURE_BIT | GL11.GL_ENABLE_BIT); + Minecraft.getMinecraft().getTextureManager().bindTexture(texture); + GL11.glEnable(GL11.GL_BLEND); + guiIn.drawTexturedModelRectFromIcon(x, y, icon, icon.getIconWidth(), icon.getIconHeight()); + GL11.glPopAttrib(); + } +} \ No newline at end of file diff --git a/src/main/java/com/falsepattern/lib/toasts/icon/ToastTexture.java b/src/main/java/com/falsepattern/lib/toasts/icon/ToastTexture.java new file mode 100644 index 0000000..c532ff1 --- /dev/null +++ b/src/main/java/com/falsepattern/lib/toasts/icon/ToastTexture.java @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2022 FalsePattern + * All Rights Reserved + *

+ * The above copyright notice, this permission notice and the word "SNEED" + * shall be included in all copies or substantial portions of the Software. + *

+ * This program 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. + *

+ * This program 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 General Public License for more details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package com.falsepattern.lib.toasts.icon; + +import com.falsepattern.lib.StableAPI; +import com.falsepattern.lib.util.RenderUtil; +import lombok.Getter; +import lombok.NonNull; + +import net.minecraft.client.gui.Gui; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +@StableAPI(since = "0.10.0") +public abstract class ToastTexture { + @Getter(onMethod_={@StableAPI(since = "0.10.0")}) + protected final IIcon icon; + @Getter(onMethod_={@StableAPI(since = "0.10.0")}) + protected final ResourceLocation texture; + + @StableAPI(since = "0.10.0") + public ToastTexture(@NonNull ResourceLocation texture, int width, int height) { + this(texture, RenderUtil.getFullTextureIcon(texture.toString(), width, height)); + } + + @StableAPI(since = "0.10.0") + public ToastTexture(@NonNull ResourceLocation texture, @NonNull IIcon icon) { + this.icon = icon; + this.texture = texture; + } + + /** + * Draws the icon at the specified position in the specified Gui + */ + @StableAPI(since = "0.10.0") + public abstract void draw(Gui guiIn, int x, int y); +} \ No newline at end of file diff --git a/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java b/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java index bef728a..3d62b8b 100644 --- a/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java +++ b/src/main/java/com/falsepattern/lib/updates/UpdateChecker.java @@ -25,7 +25,7 @@ import com.falsepattern.lib.StableAPI; import com.falsepattern.lib.dependencies.DependencyLoader; import com.falsepattern.lib.dependencies.SemanticVersion; import com.falsepattern.lib.internal.Internet; -import com.falsepattern.lib.internal.LibraryConfig; +import com.falsepattern.lib.internal.config.LibraryConfig; import com.falsepattern.lib.internal.Tags; import com.falsepattern.lib.text.FormattedText; import cpw.mods.fml.common.Loader; diff --git a/src/main/java/com/falsepattern/lib/util/RenderUtil.java b/src/main/java/com/falsepattern/lib/util/RenderUtil.java index c0ac0ab..87d8d34 100644 --- a/src/main/java/com/falsepattern/lib/util/RenderUtil.java +++ b/src/main/java/com/falsepattern/lib/util/RenderUtil.java @@ -21,11 +21,15 @@ package com.falsepattern.lib.util; import com.falsepattern.lib.StableAPI; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.val; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.IIcon; +import net.minecraft.util.Timer; import cpw.mods.fml.relauncher.ReflectionHelper; import cpw.mods.fml.relauncher.SideOnly; -import lombok.*; -import net.minecraft.client.Minecraft; -import net.minecraft.util.Timer; import static cpw.mods.fml.relauncher.Side.CLIENT; import static lombok.AccessLevel.PRIVATE; @@ -44,6 +48,56 @@ public final class RenderUtil { return (Timer) timerField.get(getMinecraft()); } + @StableAPI(since = "0.10.0") + public static IIcon getFullTextureIcon(String iconName, int width, int height) { + return new IIcon() { + @Override + public int getIconWidth() { + return width; + } + + @Override + public int getIconHeight() { + return height; + } + + @Override + public float getMinU() { + return 0; + } + + @Override + public float getMaxU() { + return 1; + } + + @Override + public float getInterpolatedU(double u) { + return (float) (u / 16D); + } + + @Override + public float getMinV() { + return 0; + } + + @Override + public float getMaxV() { + return 1; + } + + @Override + public float getInterpolatedV(double v) { + return (float) (v / 16D); + } + + @Override + public String getIconName() { + return iconName; + } + }; + } + public static float partialTick() { return MINECRAFT_TIMER.renderPartialTicks; } diff --git a/src/main/resources/assets/falsepatternlib/lang/en_US.lang b/src/main/resources/assets/falsepatternlib/lang/en_US.lang index 0583508..d6134cf 100644 --- a/src/main/resources/assets/falsepatternlib/lang/en_US.lang +++ b/src/main/resources/assets/falsepatternlib/lang/en_US.lang @@ -1,3 +1,9 @@ +config.falsepatternlib.maxtoasts=Max Toasts +config.falsepatternlib.maxtoasts.tooltip=The maximum amount of toasts to show on the screen +config.falsepatternlib.toastoffset=Toast Y Offset +config.falsepatternlib.toastoffset.tooltip=The amount of empty space from the top of the screen in pixels +config.falsepatternlib.toastalign=Toast Alignment +config.falsepatternlib.toastalign.tooltip=Which side of the screen should toasts show up on config.falsepatternlib.updatecheck=Enable update checks config.falsepatternlib.updatecheck.tooltip=Used to control whether FalsePatternLib should check for outdated mods. config.falsepatternlib.disableinternet=FalsePatternLib Offline Mode diff --git a/src/main/resources/assets/falsepatternlib/sounds.json b/src/main/resources/assets/falsepatternlib/sounds.json new file mode 100644 index 0000000..a29f455 --- /dev/null +++ b/src/main/resources/assets/falsepatternlib/sounds.json @@ -0,0 +1,14 @@ +{ + "ui.toast.in": { + "category": "master", + "sounds": [ + "toast/in" + ] + }, + "ui.toast.out": { + "category": "master", + "sounds": [ + "toast/out" + ] + } +} diff --git a/src/main/resources/assets/falsepatternlib/sounds/toast/in.ogg b/src/main/resources/assets/falsepatternlib/sounds/toast/in.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5ec26ffc277354fa15a145673b5bbbb304edb944 GIT binary patch literal 20040 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/falsepatternlib/sounds/toast/out.ogg b/src/main/resources/assets/falsepatternlib/sounds/toast/out.ogg new file mode 100644 index 0000000000000000000000000000000000000000..78d4b72fce55bffd4a4bdbeffd1bcaec1119962b GIT binary patch literal 19939 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/falsepatternlib/textures/gui/toast_dark.png b/src/main/resources/assets/falsepatternlib/textures/gui/toast_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a948e558dc668fdc72677d18a93f2877c7ca42 GIT binary patch literal 587 zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgAGVdtuOw{z`$6L>FgYknVihPpfRy@;$H8= z4id-aZ}W21mVKq5G-+X%GqN0U;A#ZUGhTRl48o3@H&zTdIOe%_tWMc-u}oPTj#`C?IXdk zY28QEj~M!~tLziq_2}d52a}G+H&xng=lJ33zw*jKFZRtw<{isB7q`WwuKnCGyCtMJ zb>=IHwS_lMDE5k|Xsk#Qwvsura@Lf{^7utBqn%o9diIHBJ$RzA(C41S%FtJDUeuS~J@2WogWu%Uy5H5WcJ&%7d|-;1om<~pH0!_G-h0;; z9e1c;-?1k%`xIlrR_-3VXrt+~gBqsAUvB8geQf96&#vVQP^ zW5%Mt4}0weOEQH1NgM=41ZROqWHAE+w-5+3UbEaktaqI1!gS-t2JPsF= zWI97`PgwWb3$+Bdj|`1`@N2x9l8o9t7O)iPJU3j_j^Q7;}_lvspJ_Pm#;>x z-_7fx#i-=K!olRypg@Rv@>|Yc`A+FgYknVihPpfRy@;$H8= z4id-aZ}W21mVKq5G-+X%GqN0U;A#ZUGhTRl48o3@H&zTdIOe%_tWMc-u}oPTj#`C?IXdk zY28QEj~M!~tLziq_2}d52a}G+H&xng=lJ33zw*jKFZRtw<{isB7q`WwuKnCGyCtMJ zb>=IHwS_lMDE5k|Xsk#Qwvsura@Lf{^7utBqn%o9diIHBJ$RzA(C41S%FtJDUeuS~J@2WogWu%Uy5H5WcJ&%7d|-;1om<~pH0!_G-h0;; z9e1c;-?1k%`xIlrR_-3VXrt+~gBqsAUvB8geQf96&#vVQP^ zW5%Mt4}0weOEQH1NgM=41ZROqWHAE+w-5+3Ub&3R)WR3@ar001Be1^@s6m49>f0004SX+uL$X=7sm z04R}lk-ba9Kp4iKwn{}S9qJ$=lA(%23q?U3YaO~2DYb%Cm*kqXLXw6{iWFDD#i8IJ zy7)EtALuH$DhPrih&cHN__auh?=^)MY45naKc3w4a`znI&*;ps`x1a*Iy{$7Nvnl5 zDfo^cCJ><+mzixXWV0Fc96yiniTV&1y?XEKI);j>%>ds3@f@?bL!2beY&n+TJ>n5o zmW#wE#4%0>B)%28;_;i{lE+_yc|NxY_(e~t)WJ#zvobe`r-`G6US+NGh?|5|b7h(8 z7_D*G$RUjsBq*q26FMBkshX5ocVD9ETSA3AjJ_6X;N&QwOx_r&RqCoz)ks%q>Zpm_ z|L19Ivol`zPzvaOb=}WNAh-`S>aP2H>bi|HAn*cQn{9uEa+?1pz24TM$3S=oxV&j= z$^me-3yeNnGMAfDfRNhQ4j~ZNw}2$wav4k)DnaW` zt9f*kf%FboJMVWY!q@eOqvl=*B$WUnfCwPuZ$h5A9yiVXVcU!GY@%wk7r;7r#d3X7 zF^pgY5Cjkb1OY?!gzc+1O!=yC|{0GhM_dh~`7%>Q;kFC&l|z&dz^wID_?cEMm5 vj1de1hycPz)_{*+tb-27&#S`k*+_H;HcKP67x3hl00000NkvXXu0mjf2M8q{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/falsepatternlib/textures/gui/toast_narrator_rounded.png b/src/main/resources/assets/falsepatternlib/textures/gui/toast_narrator_rounded.png new file mode 100644 index 0000000000000000000000000000000000000000..513691c35fdf96be19a965eeec711495f22ac26c GIT binary patch literal 690 zcmV;j0!{siP)001Be1^@s6m49>f0004SX+uL$X=7sm z04R}lk-ba9Kp4iKwn{}S9qJ$=lA(%23q?U3YaO~2DYb%Cm*kqXLXw6{iWFDD#i8IJ zy7)EtALuH$DhPrih&cHN__auh?=^)MY45naKc3w4a`znI&*;ps`x1a*Iy{$7Nvnl5 zDfo^cCJ><+mzixXWV0Fc96yiniTV&1y?XEKI);j>%>ds3@f@?bL!2beY&n+TJ>n5o zmW#wE#4%0>B)%28;_;i{lE+_yc|NxY_(e~t)WJ#zvobe`r-`G6US+NGh?|5|b7h(8 z7_D*G$RUjsBq*q26FMBkshX5ocVD9ETSA3AjJ_6X;N&QwOx_r&RqCoz)ks%q>Zpm_ z|L19Ivol`zPzvaOb=}WNAh-`S>aP2H>bi|HAn*cQn{9uEa+?1pz24TM$3S=oxV&j= z$^me-3yeNnGMAfDfR#zGLM z)x2yk6(2Dp{0Q*8-(q7$fZ@3;e<@I6POUAQ_ zsSz%~XLz~g`eI^Of)OAH5CMV!5g-T<0m4tdZbavs&^Dln7ND=*umscIPe4CLAZmcm z@N(`2u>|8O7(4}I2?hc3KLJ+%Gz?9sH|A^@qA5>CxW|_kXLUfZ_>$smm?}rK5z3>z Y8|IKZ3`vTOh5!Hn07*qoM6N<$f)n&IbN~PV literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/falsepatternlib/textures/gui/toast_white.png b/src/main/resources/assets/falsepatternlib/textures/gui/toast_white.png new file mode 100644 index 0000000000000000000000000000000000000000..c70f36685a93f901fca54985bc7b836125f8e8d7 GIT binary patch literal 587 zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgAGVdtuOw{z`$6L>FgYknVihPpfRy@;$H8= z4id-aZ}W21mVKq5G-+X%GqN0U;A#ZUGhTRl48o3@H&zTdIOe%_tWMc-u}oPTj#`C?IXdk zY28QEj~M!~tLziq_2}d52a}G+H&xng=lJ33zw*jKFZRtw<{isB7q`WwuKnCGyCtMJ zb>=IHwS_lMDE5k|Xsk#Qwvsura@Lf{^7utBqn%o9diIHBJ$RzA(C41S%FtJDUeuS~J@2WogWu%Uy5H5WcJ&%7d|-;1om<~pH0!_G-h0;; z9e1c;-?1k%`xIlrR_-3VXrt+~gBqsAUvB8geQf96&#vVQP^ zW5%Mt4}0weOEQH1NgM=41ZROqWHAE+w-5+3UbEaktaqI1!gS-t2JPsF= zWI7`yCPm)xeC)WGIia`my@Q3h{a(k;4qb(lRWf_aCqF1%yEUSx@e6Oos;#p)F83O) z+s*5t#i-=K!olRypg@Rv@>|Yc`A+iRwa literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/falsepatternlib/textures/gui/toast_white_rounded.png b/src/main/resources/assets/falsepatternlib/textures/gui/toast_white_rounded.png new file mode 100644 index 0000000000000000000000000000000000000000..b241f6a51a1925d835f99e54ed9870c5b93f0cdc GIT binary patch literal 611 zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgAGVdtuOw{z`$6L>FgYknVihPpfRy@;$H8= z4id-aZ}W21mVKq5G-+X%GqN0U;A#ZUGhTRl48o3@H&zTdIOe%_tWMc-u}oPTj#`C?IXdk zY28QEj~M!~tLziq_2}d52a}G+H&xng=lJ33zw*jKFZRtw<{isB7q`WwuKnCGyCtMJ zb>=IHwS_lMDE5k|Xsk#Qwvsura@Lf{^7utBqn%o9diIHBJ$RzA(C41S%FtJDUeuS~J@2WogWu%Uy5H5WcJ&%7d|-;1om<~pH0!_G-h0;; z9e1c;-?1k%`xIlrR_-3VXrt+~gBqsAUvB8geQf96&#vVQP^ zW5%Mt4}0weOEQH1NgM=41ZROqWHAE+w-5+3UbubZ8Y4Sc;nff9)aDvIU=Rv kf4psb8F}%T*8OjGN-yLsxNb&e0v*ZV>FVdQ&MBb@0MIH5H2?qr literal 0 HcmV?d00001