Stop blocking all UI during path playback (closes #269)

Instead, just copy the timeline before playback.
This commit is contained in:
Jonas Herzig
2020-08-29 13:20:59 +02:00
parent 9314eab7ff
commit 098300f0db

View File

@@ -29,14 +29,11 @@ import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo; import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.GuiContainer; import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel; import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.element.AbstractGuiClickable;
import de.johni0702.minecraft.gui.element.AbstractGuiElement;
import de.johni0702.minecraft.gui.element.GuiElement; import de.johni0702.minecraft.gui.element.GuiElement;
import de.johni0702.minecraft.gui.element.GuiHorizontalScrollbar; import de.johni0702.minecraft.gui.element.GuiHorizontalScrollbar;
import de.johni0702.minecraft.gui.element.GuiLabel; import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.element.GuiTexturedButton; import de.johni0702.minecraft.gui.element.GuiTexturedButton;
import de.johni0702.minecraft.gui.element.GuiTooltip; import de.johni0702.minecraft.gui.element.GuiTooltip;
import de.johni0702.minecraft.gui.element.IGuiClickable;
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar; import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
import de.johni0702.minecraft.gui.element.advanced.GuiTimelineTime; import de.johni0702.minecraft.gui.element.advanced.GuiTimelineTime;
import de.johni0702.minecraft.gui.layout.CustomLayout; import de.johni0702.minecraft.gui.layout.CustomLayout;
@@ -46,7 +43,6 @@ import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.popup.GuiInfoPopup; import de.johni0702.minecraft.gui.popup.GuiInfoPopup;
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup; import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
import de.johni0702.minecraft.gui.utils.Colors; import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension; import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint; import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
import de.johni0702.minecraft.gui.utils.lwjgl.WritablePoint; import de.johni0702.minecraft.gui.utils.lwjgl.WritablePoint;
@@ -102,20 +98,8 @@ public class GuiPathing {
public final GuiTexturedButton renderButton = new GuiTexturedButton().onClick(new Runnable() { public final GuiTexturedButton renderButton = new GuiTexturedButton().onClick(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!preparePathsForPlayback(false)) return; Timeline timeline = preparePathsForPlayback(false);
if (timeline == null) return;
// Clone the timeline passed to the settings gui as it may be stored for later rendering in a queue
SPTimeline spTimeline = mod.getCurrentTimeline();
Timeline timeline;
try {
TimelineSerialization serialization = new TimelineSerialization(spTimeline, null);
String serialized = serialization.serialize(Collections.singletonMap("", spTimeline.getTimeline()));
timeline = serialization.deserialize(serialized).get("");
} catch (Throwable t) {
error(LOGGER, replayHandler.getOverlay(), CrashReport.create(t, "Cloning timeline"), () -> {});
return;
}
new GuiRenderSettings(replayHandler, timeline).display(); new GuiRenderSettings(replayHandler, timeline).display();
} }
}).setSize(20, 20).setTexture(ReplayMod.TEXTURE, ReplayMod.TEXTURE_SIZE).setTexturePosH(40, 0) }).setSize(20, 20).setTexture(ReplayMod.TEXTURE, ReplayMod.TEXTURE_SIZE).setTexturePosH(40, 0)
@@ -224,48 +208,6 @@ public class GuiPathing {
.addElements(new HorizontalLayout.Data(0.5), .addElements(new HorizontalLayout.Data(0.5),
playPauseButton, renderButton, positionKeyframeButton, timeKeyframeButton, timelinePanel); playPauseButton, renderButton, positionKeyframeButton, timeKeyframeButton, timelinePanel);
/**
* IGuiClickable dummy component that is inserted at a high level.
* During path playback, this catches all click events and forwards them to the
* abort path playback button.
* Dragging does not have to be intercepted as every GUI element should only
* respond to dragging events after it has received and handled a click event.
*/
private final IGuiClickable clickCatcher = new AbstractGuiClickable() {
@Override
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
if (player.isActive()) {
// Make sure the mouse is always visible during path playback
// even if the game closes the overlay for some reason (e.g. world change)
replayHandler.getOverlay().setMouseVisible(true);
}
}
@Override
protected AbstractGuiElement getThis() {
return this;
}
@Override
protected ReadableDimension calcMinSize() {
return new Dimension(0, 0);
}
@Override
public boolean mouseClick(ReadablePoint position, int button) {
if (player.isActive()) {
playPauseButton.mouseClick(position, button);
return true;
}
return false;
}
@Override
public int getLayer() {
return player.isActive() ? 10 : 0;
}
};
private final ReplayMod core; private final ReplayMod core;
private final ReplayModSimplePathing mod; private final ReplayModSimplePathing mod;
private final ReplayHandler replayHandler; private final ReplayHandler replayHandler;
@@ -308,14 +250,16 @@ public class GuiPathing {
player.getFuture().cancel(false); player.getFuture().cancel(false);
} else { } else {
boolean ignoreTimeKeyframes = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT); boolean ignoreTimeKeyframes = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
Path timePath = mod.getCurrentTimeline().getTimePath();
if (!preparePathsForPlayback(ignoreTimeKeyframes)) return; Timeline timeline = preparePathsForPlayback(ignoreTimeKeyframes);
if (timeline == null) return;
Path timePath = new SPTimeline(timeline).getTimePath();
timePath.setActive(!ignoreTimeKeyframes); timePath.setActive(!ignoreTimeKeyframes);
// Start from cursor time unless the control key is pressed (then start from beginning) // Start from cursor time unless the control key is pressed (then start from beginning)
int startTime = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)? 0 : GuiPathing.this.timeline.getCursorPosition(); int startTime = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)? 0 : GuiPathing.this.timeline.getCursorPosition();
ListenableFuture<Void> future = player.start(mod.getCurrentTimeline().getTimeline(), startTime); ListenableFuture<Void> future = player.start(timeline, startTime);
overlay.setCloseable(false); overlay.setCloseable(false);
overlay.setMouseVisible(true); overlay.setMouseVisible(true);
core.printInfoToChat("replaymod.chat.pathstarted"); core.printInfoToChat("replaymod.chat.pathstarted");
@@ -328,14 +272,12 @@ public class GuiPathing {
core.printInfoToChat("replaymod.chat.pathfinished"); core.printInfoToChat("replaymod.chat.pathfinished");
} }
overlay.setCloseable(true); overlay.setCloseable(true);
timePath.setActive(true);
} }
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
t.printStackTrace(); t.printStackTrace();
overlay.setCloseable(true); overlay.setCloseable(true);
timePath.setActive(true);
} }
}); });
} }
@@ -407,13 +349,12 @@ public class GuiPathing {
} }
}); });
overlay.addElements(null, panel, clickCatcher); overlay.addElements(null, panel);
overlay.setLayout(new CustomLayout<GuiReplayOverlay>(overlay.getLayout()) { overlay.setLayout(new CustomLayout<GuiReplayOverlay>(overlay.getLayout()) {
@Override @Override
protected void layout(GuiReplayOverlay container, int width, int height) { protected void layout(GuiReplayOverlay container, int width, int height) {
pos(panel, 10, y(overlay.topPanel) + height(overlay.topPanel) + 3); pos(panel, 10, y(overlay.topPanel) + height(overlay.topPanel) + 3);
size(panel, width - 20, 40); size(panel, width - 20, 40);
size(clickCatcher, 0, 0);
} }
}); });
@@ -528,8 +469,26 @@ public class GuiPathing {
}).start(); }).start();
} }
private boolean preparePathsForPlayback(boolean ignoreTimeKeyframes) { private Timeline preparePathsForPlayback(boolean ignoreTimeKeyframes) {
SPTimeline timeline = mod.getCurrentTimeline(); SPTimeline spTimeline = mod.getCurrentTimeline();
if (!validatePathsForPlayback(spTimeline, ignoreTimeKeyframes)) {
return null;
}
try {
TimelineSerialization serialization = new TimelineSerialization(spTimeline, null);
String serialized = serialization.serialize(Collections.singletonMap("", spTimeline.getTimeline()));
Timeline timeline = serialization.deserialize(serialized).get("");
timeline.getPaths().forEach(Path::updateAll);
return timeline;
} catch (Throwable t) {
error(LOGGER, replayHandler.getOverlay(), CrashReport.create(t, "Cloning timeline"), () -> {});
return null;
}
}
private boolean validatePathsForPlayback(SPTimeline timeline, boolean ignoreTimeKeyframes) {
timeline.getTimeline().getPaths().forEach(Path::updateAll); timeline.getTimeline().getPaths().forEach(Path::updateAll);
// Make sure there are at least two position keyframes // Make sure there are at least two position keyframes