From 83cb459957559bd67383b2494f005d6d8f41a61b Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 24 Jul 2021 11:54:14 +0200 Subject: [PATCH] Fix keyframes being required to open render queue window Half the reason we swapped the render queue / settings parent relationship was so we don't need to go through the settings screen to access the queue. But for some reason I stopped half way through and didn't also move the "You need at last two keyframes." popup. This commit rectifies that. --- .../java/com/replaymod/core/utils/Result.java | 142 ++++++++++++++++++ .../replaymod/render/gui/GuiRenderQueue.java | 22 ++- .../simplepathing/gui/GuiPathing.java | 37 ++--- 3 files changed, 171 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/replaymod/core/utils/Result.java diff --git a/src/main/java/com/replaymod/core/utils/Result.java b/src/main/java/com/replaymod/core/utils/Result.java new file mode 100644 index 00000000..d2c70c2f --- /dev/null +++ b/src/main/java/com/replaymod/core/utils/Result.java @@ -0,0 +1,142 @@ +package com.replaymod.core.utils; + +import java.util.function.Consumer; +import java.util.function.Function; + +public abstract class Result { + + public static OkImpl ok(Ok value) { + return new OkImpl<>(value); + } + + public static ErrImpl err(Err value) { + return new ErrImpl<>(value); + } + + public abstract boolean isOk(); + public abstract boolean isErr(); + public abstract Ok okOrNull(); + public abstract Err errOrNull(); + public abstract void ifOk(Consumer consumer); + public abstract void ifErr(Consumer consumer); + public abstract Ok okOrElse(Function orElse); + public abstract Err errOrElse(Function orElse); + public abstract Result mapOk(Function func); + public abstract Result mapErr(Function func); + + private static class OkImpl extends Result { + private final Ok value; + + public OkImpl(Ok value) { + this.value = value; + } + + @Override + public boolean isOk() { + return true; + } + + @Override + public boolean isErr() { + return false; + } + + @Override + public Ok okOrNull() { + return this.value; + } + + @Override + public Err errOrNull() { + return null; + } + + @Override + public void ifOk(Consumer consumer) { + consumer.accept(this.value); + } + + @Override + public void ifErr(Consumer consumer) { + } + + @Override + public Ok okOrElse(Function orElse) { + return this.value; + } + + @Override + public Err errOrElse(Function orElse) { + return orElse.apply(this.value); + } + + @Override + public Result mapOk(Function func) { + return ok(func.apply(this.value)); + } + + @SuppressWarnings("unchecked") + @Override + public Result mapErr(Function func) { + return (Result) this; + } + } + + private static class ErrImpl extends Result { + private final Err value; + + public ErrImpl(Err value) { + this.value = value; + } + + @Override + public boolean isOk() { + return false; + } + + @Override + public boolean isErr() { + return true; + } + + @Override + public Ok okOrNull() { + return null; + } + + @Override + public Err errOrNull() { + return this.value; + } + + @Override + public void ifOk(Consumer consumer) { + } + + @Override + public void ifErr(Consumer consumer) { + consumer.accept(this.value); + } + + @Override + public Ok okOrElse(Function orElse) { + return orElse.apply(this.value); + } + + @Override + public Err errOrElse(Function orElse) { + return this.value; + } + + @SuppressWarnings("unchecked") + @Override + public Result mapOk(Function func) { + return (Result) this; + } + + @Override + public Result mapErr(Function func) { + return err(func.apply(this.value)); + } + } +} diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java index 8e9d92ea..a019b565 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java @@ -2,6 +2,7 @@ package com.replaymod.render.gui; import com.google.common.collect.Iterables; import com.replaymod.core.ReplayMod; +import com.replaymod.core.utils.Result; import com.replaymod.core.utils.Utils; import com.replaymod.core.versions.MCVer; import com.replaymod.render.RenderSettings; @@ -30,6 +31,7 @@ import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.GridLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; +import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.utils.Colors; import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; @@ -88,7 +90,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements private final AbstractGuiScreen container; private final ReplayHandler replayHandler; private final Set selectedEntries = new HashSet<>(); - private final Supplier timelineSupplier; + private final Supplier> timelineSupplier; private boolean opened; { @@ -113,7 +115,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements private final ReplayModRender mod = ReplayModRender.instance; private final List jobs = mod.getRenderQueue(); - public GuiRenderQueue(AbstractGuiScreen container, ReplayHandler replayHandler, Supplier timelineSupplier) { + public GuiRenderQueue(AbstractGuiScreen container, ReplayHandler replayHandler, Supplier> timelineSupplier) { super(container); this.container = container; this.replayHandler = replayHandler; @@ -127,7 +129,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements list.getListPanel().addElements(null, new Entry(renderJob)); } - addButton.onClick(this::addButtonClicked); + addButton.onClick(() -> addButtonClicked().ifErr(lines -> GuiInfoPopup.open(container, lines))); editButton.onClick(() -> { Entry job = selectedEntries.iterator().next(); @@ -267,15 +269,12 @@ public class GuiRenderQueue extends AbstractGuiPopup implements }); } - private GuiRenderSettings addButtonClicked() { - Timeline timeline = timelineSupplier.get(); - if (timeline != null) { + private Result addButtonClicked() { + return timelineSupplier.get().mapOk(timeline -> { GuiRenderSettings popup = addJob(timeline); popup.open(); return popup; - } else { - return null; - } + }); } public GuiRenderSettings addJob(Timeline timeline) { @@ -317,9 +316,8 @@ public class GuiRenderQueue extends AbstractGuiPopup implements @Override public void open() { if (jobs.isEmpty() && timelineSupplier != null) { - if (addButtonClicked() == null) { - close(); - } + addButtonClicked().ifErr(lines -> + GuiInfoPopup.open(container, lines).onClosed(this::close)); return; } diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index cdce5a51..8df8f8f2 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -6,6 +6,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.replaymod.core.ReplayMod; +import com.replaymod.core.utils.Result; import com.replaymod.core.utils.Utils; import com.replaymod.pathing.gui.GuiKeyframeRepository; import com.replaymod.pathing.player.RealtimeTimelinePlayer; @@ -101,8 +102,6 @@ public class GuiPathing { public final GuiButton renderButton = new GuiButton().onClick(new Runnable() { @Override public void run() { - Timeline timeline = preparePathsForPlayback(false); - if (timeline == null) return; GuiScreen screen = GuiRenderSettings.createBaseScreen(); new GuiRenderQueue(screen, replayHandler, () -> preparePathsForPlayback(false)) { @Override @@ -263,7 +262,10 @@ public class GuiPathing { } else { boolean ignoreTimeKeyframes = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); - Timeline timeline = preparePathsForPlayback(ignoreTimeKeyframes); + Timeline timeline = preparePathsForPlayback(ignoreTimeKeyframes).okOrElse(err -> { + GuiInfoPopup.open(overlay, err); + return null; + }); if (timeline == null) return; Path timePath = new SPTimeline(timeline).getTimePath(); @@ -497,11 +499,12 @@ public class GuiPathing { }).start(); } - private Timeline preparePathsForPlayback(boolean ignoreTimeKeyframes) { + private Result preparePathsForPlayback(boolean ignoreTimeKeyframes) { SPTimeline spTimeline = mod.getCurrentTimeline(); - if (!validatePathsForPlayback(spTimeline, ignoreTimeKeyframes)) { - return null; + String[] errors = validatePathsForPlayback(spTimeline, ignoreTimeKeyframes); + if (errors != null) { + return Result.err(errors); } try { @@ -509,24 +512,23 @@ public class GuiPathing { String serialized = serialization.serialize(Collections.singletonMap("", spTimeline.getTimeline())); Timeline timeline = serialization.deserialize(serialized).get(""); timeline.getPaths().forEach(Path::updateAll); - return timeline; + return Result.ok(timeline); } catch (Throwable t) { error(LOGGER, replayHandler.getOverlay(), CrashReport.create(t, "Cloning timeline"), () -> {}); - return null; + return Result.err(null); } } - private boolean validatePathsForPlayback(SPTimeline timeline, boolean ignoreTimeKeyframes) { + private String[] validatePathsForPlayback(SPTimeline timeline, boolean ignoreTimeKeyframes) { timeline.getTimeline().getPaths().forEach(Path::updateAll); // Make sure there are at least two position keyframes if (timeline.getPositionPath().getSegments().isEmpty()) { - GuiInfoPopup.open(replayHandler.getOverlay(), "replaymod.chat.morekeyframes"); - return false; + return new String[]{ "replaymod.chat.morekeyframes" }; } if (ignoreTimeKeyframes) { - return true; + return null; } // Make sure time keyframes's values are monotonically increasing @@ -535,22 +537,21 @@ public class GuiPathing { int time = keyframe.getValue(TimestampProperty.PROPERTY).orElseThrow(IllegalStateException::new); if (time < lastTime) { // We are going backwards in time - GuiInfoPopup.open(replayHandler.getOverlay(), + return new String[]{ "replaymod.error.negativetime1", "replaymod.error.negativetime2", - "replaymod.error.negativetime3"); - return false; + "replaymod.error.negativetime3" + }; } lastTime = time; } // Make sure there are at least two time keyframes if (timeline.getTimePath().getSegments().isEmpty()) { - GuiInfoPopup.open(replayHandler.getOverlay(), "replaymod.chat.morekeyframes"); - return false; + return new String[]{ "replaymod.chat.morekeyframes" }; } - return true; + return null; } public void zoomTimeline(double factor) {