diff --git a/jGui b/jGui index 4125b3ac..163cfe2f 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 4125b3ac207b7afee753c0503e07f8f7899a9950 +Subproject commit 163cfe2f8a9caa6792dc262c139afc066d371cfb diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java index 2ca6ba72..72f1368c 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiKeyframeTimeline.java @@ -121,24 +121,42 @@ public class GuiKeyframeTimeline extends AbstractGuiTimeline= endTime || endFrameTime <= startTime) { - continue; // Segment out of display range - } + drawQuadOnSegment(renderer, visibleWidth, segment, BORDER_TOP + 1, 0xFF0088FF); + } - double relativeStart = startFrameTime - startTime; - double relativeEnd = endFrameTime - startTime; - int startX = BORDER_LEFT + Math.max(0, (int) (relativeStart / visibleTime * visibleWidth) + KEYFRAME_SIZE / 2 + 1); - int endX = BORDER_LEFT + Math.min(visibleWidth, (int) (relativeEnd / visibleTime * visibleWidth) - KEYFRAME_SIZE / 2); - if (startX < endX) { - renderer.drawRect(startX + 1, BORDER_TOP + 1, endX - startX - 2, KEYFRAME_SIZE - 2, 0xFF0088FF); + // Draw red quads on time path segments that would require time going backwards + for (PathSegment segment : mod.getCurrentTimeline().getPaths().get(GuiPathing.TIME_PATH).getSegments()) { + long startTimestamp = segment.getStartKeyframe().getValue(TimestampProperty.PROPERTY).orElseThrow(IllegalStateException::new); + long endTimestamp = segment.getEndKeyframe().getValue(TimestampProperty.PROPERTY).orElseThrow(IllegalStateException::new); + if (endTimestamp >= startTimestamp) { + continue; // All is fine, time is not moving backwards } + drawQuadOnSegment(renderer, visibleWidth, segment, BORDER_TOP + KEYFRAME_SIZE + 1, 0xFFFF0000); } super.drawTimelineCursor(renderer, size); } + private void drawQuadOnSegment(GuiRenderer renderer, int visibleWidth, PathSegment segment, int y, int color) { + int startTime = getOffset(); + int visibleTime = (int) (getZoom() * getLength()); + int endTime = getOffset() + visibleTime; + + long startFrameTime = segment.getStartKeyframe().getTime(); + long endFrameTime = segment.getEndKeyframe().getTime(); + if (startFrameTime >= endTime || endFrameTime <= startTime) { + return; // Segment out of display range + } + + double relativeStart = startFrameTime - startTime; + double relativeEnd = endFrameTime - startTime; + int startX = BORDER_LEFT + Math.max(0, (int) (relativeStart / visibleTime * visibleWidth) + KEYFRAME_SIZE / 2 + 1); + int endX = BORDER_LEFT + Math.min(visibleWidth, (int) (relativeEnd / visibleTime * visibleWidth) - KEYFRAME_SIZE / 2); + if (startX < endX) { + renderer.drawRect(startX + 1, y, endX - startX - 2, KEYFRAME_SIZE - 2, color); + } + } + /** * Returns the keyframe at the specified position. * @param position The raw position diff --git a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java index ab8aae28..8e0236b1 100644 --- a/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java +++ b/src/main/java/com/replaymod/simplepathing/gui/GuiPathing.java @@ -38,6 +38,7 @@ import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.HorizontalLayout; import de.johni0702.minecraft.gui.layout.VerticalLayout; import de.johni0702.minecraft.gui.popup.AbstractGuiPopup; +import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.popup.GuiYesNoPopup; import de.johni0702.minecraft.gui.utils.Colors; import net.minecraft.entity.Entity; @@ -75,7 +76,7 @@ public class GuiPathing { public final GuiTexturedButton renderButton = new GuiTexturedButton().onClick(new Runnable() { @Override public void run() { - preparePathsForPlayback(); + if (!preparePathsForPlayback()) return; new GuiRenderSettings(replayHandler, mod.getCurrentTimeline()).display(); } }).setSize(20, 20).setTexture(ReplayMod.TEXTURE, ReplayMod.TEXTURE_SIZE).setTexturePosH(40, 0); @@ -231,7 +232,7 @@ public class GuiPathing { Timeline timeline = mod.getCurrentTimeline(); Path timePath = timeline.getPaths().get(TIME_PATH); - preparePathsForPlayback(); + if (!preparePathsForPlayback()) return; timePath.setActive(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)); ListenableFuture future = player.start(timeline); @@ -438,10 +439,27 @@ public class GuiPathing { }).start(); } - private void preparePathsForPlayback() { + private boolean preparePathsForPlayback() { Timeline timeline = mod.getCurrentTimeline(); timeline.getPaths().get(TIME_PATH).updateAll(); timeline.getPaths().get(POSITION_PATH).updateAll(); + + // Make sure time keyframes's values are monotonically increasing + int lastTime = 0; + for (Keyframe keyframe : timeline.getPaths().get(TIME_PATH).getKeyframes()) { + int time = keyframe.getValue(TimestampProperty.PROPERTY).orElseThrow(IllegalStateException::new); + if (time < lastTime) { + // We are going backwards in time + GuiInfoPopup.open(replayHandler.getOverlay(), + "replaymod.error.negativetime1", + "replaymod.error.negativetime2", + "replaymod.error.negativetime3"); + return false; + } + lastTime = time; + } + + return true; } public void zoomTimeline(double factor) { diff --git a/src/main/resources/assets/replaymod/lang/en_US.lang b/src/main/resources/assets/replaymod/lang/en_US.lang index 1c660296..ecdf54ef 100644 --- a/src/main/resources/assets/replaymod/lang/en_US.lang +++ b/src/main/resources/assets/replaymod/lang/en_US.lang @@ -485,6 +485,9 @@ replaymod.gui.objects=Custom Objects #Errors replaymod.error.unknownrestriction1=This replay cannot be played with your current version. replaymod.error.unknownrestriction2=It tried to enforce %s which is unknown. +replaymod.error.negativetime1=Some of your time keyframes are out of order. +replaymod.error.negativetime2=Going backwards in time is not supported. +replaymod.error.negativetime3=The invalid parts are marked in red. #Replay Mod Incompatibility Warning replaymod.gui.modwarning.title=Incompatibility detected