diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/GuiKeyframeRepository.java b/src/main/java/eu/crushedpixel/replaymod/gui/GuiKeyframeRepository.java index a5109335..7f3a4014 100644 --- a/src/main/java/eu/crushedpixel/replaymod/gui/GuiKeyframeRepository.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/GuiKeyframeRepository.java @@ -7,6 +7,7 @@ import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay; import eu.crushedpixel.replaymod.holders.Keyframe; import eu.crushedpixel.replaymod.holders.KeyframeSet; import eu.crushedpixel.replaymod.replay.ReplayHandler; +import eu.crushedpixel.replaymod.utils.CameraPathValidator; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; @@ -135,10 +136,15 @@ public class GuiKeyframeRepository extends GuiScreen implements GuiReplayOverlay Keyframe[] keyframes = kfs.toArray(new Keyframe[ReplayHandler.getAllKeyframes().size()]); KeyframeSet newSet = new KeyframeSet(I18n.format("replaymod.gui.keyframerepository.preset.defaultname"), keyframes); - if(newSet.getPositionKeyframeCount() < 2 || newSet.getTimeKeyframeCount() < 1) { - message = I18n.format("replaymod.chat.morekeyframes"); + + try { + CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes()); + } catch(CameraPathValidator.InvalidCameraPathException e) { + message = e.getLocalizedMessage(); break; - } else if(keyframeSetList.getCopyOfElements().contains(newSet)) { + } + + if(keyframeSetList.getCopyOfElements().contains(newSet)) { message = I18n.format("replaymod.gui.keyframerepository.duplicate"); break; } diff --git a/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java b/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java index bad34d61..e9d5149d 100755 --- a/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java +++ b/src/main/java/eu/crushedpixel/replaymod/gui/overlay/GuiReplayOverlay.java @@ -1,7 +1,6 @@ package eu.crushedpixel.replaymod.gui.overlay; import eu.crushedpixel.replaymod.ReplayMod; -import eu.crushedpixel.replaymod.chat.ChatMessageHandler; import eu.crushedpixel.replaymod.entities.CameraEntity; import eu.crushedpixel.replaymod.gui.GuiMouseInput; import eu.crushedpixel.replaymod.gui.GuiRenderSettings; @@ -9,11 +8,12 @@ import eu.crushedpixel.replaymod.gui.GuiReplaySpeedSlider; import eu.crushedpixel.replaymod.gui.elements.*; import eu.crushedpixel.replaymod.gui.elements.timelines.GuiKeyframeTimeline; import eu.crushedpixel.replaymod.gui.elements.timelines.GuiMarkerTimeline; -import eu.crushedpixel.replaymod.holders.Keyframe; import eu.crushedpixel.replaymod.holders.AdvancedPosition; +import eu.crushedpixel.replaymod.holders.Keyframe; import eu.crushedpixel.replaymod.holders.TimestampValue; import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry; import eu.crushedpixel.replaymod.replay.ReplayHandler; +import eu.crushedpixel.replaymod.utils.CameraPathValidator; import eu.crushedpixel.replaymod.utils.MouseUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityOtherPlayerMP; @@ -98,12 +98,14 @@ public class GuiReplayOverlay extends Gui { private final GuiElement buttonExport = texturedButton(BUTTON_EXPORT_X, BOTTOM_ROW, 40, 0, 20, new Runnable() { @Override public void run() { - //if not enough keyframes, abort and leave chat message - if(ReplayHandler.getPositionKeyframes().size() < 2 || ReplayHandler.getTimeKeyframes().size() < 1) { - ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.morekeyframes", ChatMessageHandler.ChatMessageType.WARNING); - } else { - mc.displayGuiScreen(new GuiRenderSettings()); + try { + CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes()); + } catch(CameraPathValidator.InvalidCameraPathException e) { + e.printToChat(); + return; } + mc.displayGuiScreen(new GuiRenderSettings()); + } }, "replaymod.gui.ingame.menu.renderpath"); diff --git a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java index 636ec22f..4ab18c57 100755 --- a/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java +++ b/src/main/java/eu/crushedpixel/replaymod/replay/ReplayProcess.java @@ -10,6 +10,7 @@ import eu.crushedpixel.replaymod.interpolation.GenericSplineInterpolation; import eu.crushedpixel.replaymod.settings.RenderOptions; import eu.crushedpixel.replaymod.timer.EnchantmentTimer; import eu.crushedpixel.replaymod.timer.ReplayTimer; +import eu.crushedpixel.replaymod.utils.CameraPathValidator; import eu.crushedpixel.replaymod.video.VideoRenderer; import lombok.Getter; import net.minecraft.client.Minecraft; @@ -78,9 +79,10 @@ public class ReplayProcess { ReplayMod.chatMessageHandler.initialize(); - //if not enough keyframes, abort and leave chat message - if(ReplayHandler.getPositionKeyframes().size() < 2 || ReplayHandler.getTimeKeyframes().size() < 1) { - ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.morekeyframes", ChatMessageType.WARNING); + try { + CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes()); + } catch(CameraPathValidator.InvalidCameraPathException e) { + e.printToChat(); return; } diff --git a/src/main/java/eu/crushedpixel/replaymod/utils/CameraPathValidator.java b/src/main/java/eu/crushedpixel/replaymod/utils/CameraPathValidator.java new file mode 100644 index 00000000..a2c22a84 --- /dev/null +++ b/src/main/java/eu/crushedpixel/replaymod/utils/CameraPathValidator.java @@ -0,0 +1,41 @@ +package eu.crushedpixel.replaymod.utils; + +import eu.crushedpixel.replaymod.ReplayMod; +import eu.crushedpixel.replaymod.chat.ChatMessageHandler; +import eu.crushedpixel.replaymod.holders.AdvancedPosition; +import eu.crushedpixel.replaymod.holders.Keyframe; +import eu.crushedpixel.replaymod.holders.TimestampValue; +import eu.crushedpixel.replaymod.interpolation.KeyframeList; +import net.minecraft.client.resources.I18n; + +public class CameraPathValidator { + + public static class InvalidCameraPathException extends Exception { + public InvalidCameraPathException(String message) { + super(message); + } + + @Override + public String getLocalizedMessage() { + return I18n.format(getMessage()); + } + + public void printToChat() { + ReplayMod.chatMessageHandler.addLocalizedChatMessage(getMessage(), ChatMessageHandler.ChatMessageType.WARNING); + } + } + + public static void validateCameraPath(KeyframeList positionKeyframes, KeyframeList timeKeyframes) + throws InvalidCameraPathException { + + if(positionKeyframes.size() < 2 || timeKeyframes.size() < 2) { + throw new InvalidCameraPathException("replaymod.chat.morekeyframes"); + } + + int previousTimestamp = -1; + for(Keyframe timeKeyframe : timeKeyframes) { + if(timeKeyframe.getValue().asInt() < previousTimestamp) throw new InvalidCameraPathException("replaymod.chat.negativetime"); + previousTimestamp = timeKeyframe.getValue().asInt(); + } + } +} diff --git a/src/main/resources/assets/replaymod/lang/en_US.lang b/src/main/resources/assets/replaymod/lang/en_US.lang index 83dd77a6..337ecaea 100644 --- a/src/main/resources/assets/replaymod/lang/en_US.lang +++ b/src/main/resources/assets/replaymod/lang/en_US.lang @@ -42,6 +42,7 @@ replaymod.chat.addedmarker=Event Marker has been added #Chat messages displayed in Replay Viewer replaymod.chat.morekeyframes=At least 2 position keyframes and 1 time keyframe required +replaymod.chat.negativetime=Camera Paths can't play time backwards. Please consult your nearest time lord for assistance. replaymod.chat.pathstarted=Camera Path started replaymod.chat.pathfinished=Camera Path finished replaymod.chat.pathinterrupted=Camera Path canceled