203 lines
9.5 KiB
Java
203 lines
9.5 KiB
Java
package com.replaymod.editor.gui;
|
|
|
|
import com.google.gson.JsonObject;
|
|
import com.replaymod.core.utils.Utils;
|
|
import com.replaymod.replaystudio.data.Marker;
|
|
import com.replaymod.replaystudio.filter.ChangeTimestampFilter;
|
|
import com.replaymod.replaystudio.filter.RemoveFilter;
|
|
import com.replaymod.replaystudio.filter.SquashFilter;
|
|
import com.replaymod.replaystudio.replay.ReplayFile;
|
|
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
|
import com.replaymod.replaystudio.replay.ZipReplayFile;
|
|
import com.replaymod.replaystudio.stream.PacketStream;
|
|
import com.replaymod.replaystudio.studio.ReplayStudio;
|
|
import de.johni0702.minecraft.gui.container.GuiPanel;
|
|
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
import de.johni0702.minecraft.gui.element.GuiNumberField;
|
|
import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu;
|
|
import de.johni0702.minecraft.gui.layout.GridLayout;
|
|
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
|
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|
import net.minecraft.client.resources.I18n;
|
|
import net.minecraft.crash.CrashReport;
|
|
import org.apache.commons.io.FilenameUtils;
|
|
import org.apache.commons.io.IOCase;
|
|
import org.apache.commons.io.filefilter.SuffixFileFilter;
|
|
import org.lwjgl.util.Dimension;
|
|
|
|
import java.io.File;
|
|
import java.io.FileFilter;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
|
|
import static com.replaymod.editor.ReplayModEditor.LOGGER;
|
|
import static java.util.Optional.ofNullable;
|
|
|
|
public class GuiTrimPanel extends GuiPanel {
|
|
private static GuiNumberField newGuiNumberField() {
|
|
return new GuiNumberField().setMaxLength(2).setSize(20, 20).setValidateOnFocusChange(true);
|
|
}
|
|
|
|
// Special value indicating no replay files were found
|
|
private static final File NO_REPLAY = new File(".");
|
|
// Special value for the initial "Select Marker Keyframe" entry
|
|
private static final Marker NO_MARKER = new Marker(); static {NO_MARKER.setTime(-1);}
|
|
|
|
private final GuiReplayEditor gui;
|
|
|
|
public final GuiDropdownMenu<File> inputReplays = new GuiDropdownMenu<File>(this)
|
|
.setMinSize(new Dimension(200, 20)).onSelection(i -> updateSelectedReplay())
|
|
.setToString(f -> f == NO_REPLAY ? "" : FilenameUtils.getBaseName(f.getName()));
|
|
|
|
public final GuiNumberField startHour = newGuiNumberField();
|
|
public final GuiNumberField startMin = newGuiNumberField();
|
|
public final GuiNumberField startSec = newGuiNumberField();
|
|
public final GuiNumberField startMilli = newGuiNumberField().setSize(40, 20).setMaxLength(4);
|
|
public final GuiDropdownMenu<Marker> startMarker = new GuiDropdownMenu<>();
|
|
|
|
public final GuiNumberField endHour = newGuiNumberField();
|
|
public final GuiNumberField endMin = newGuiNumberField();
|
|
public final GuiNumberField endSec = newGuiNumberField();
|
|
public final GuiNumberField endMilli = newGuiNumberField().setSize(40, 20).setMaxLength(4);
|
|
public final GuiDropdownMenu<Marker> endMarker = new GuiDropdownMenu<>();
|
|
|
|
public final GuiPanel timePanel = new GuiPanel(this)
|
|
.setLayout(new GridLayout().setCellsEqualSize(false).setSpacingX(20).setSpacingY(5).setColumns(3))
|
|
.addElements(new GridLayout.Data(0, 0.5),
|
|
new GuiLabel().setI18nText("replaymod.gui.start"),
|
|
new GuiPanel().setLayout(new HorizontalLayout().setSpacing(2)).addElements(
|
|
new HorizontalLayout.Data(0.5),
|
|
startHour, new GuiLabel().setI18nText("replaymod.gui.hours"),
|
|
startMin, new GuiLabel().setI18nText("replaymod.gui.minutes"),
|
|
startSec, new GuiLabel().setI18nText("replaymod.gui.seconds"),
|
|
startMilli, new GuiLabel().setI18nText("replaymod.gui.milliseconds")
|
|
), startMarker,
|
|
new GuiLabel().setI18nText("replaymod.gui.end"),
|
|
new GuiPanel().setLayout(new HorizontalLayout().setSpacing(2)).addElements(
|
|
new HorizontalLayout.Data(0.5),
|
|
endHour, new GuiLabel().setI18nText("replaymod.gui.hours"),
|
|
endMin, new GuiLabel().setI18nText("replaymod.gui.minutes"),
|
|
endSec, new GuiLabel().setI18nText("replaymod.gui.seconds"),
|
|
endMilli, new GuiLabel().setI18nText("replaymod.gui.milliseconds")
|
|
), endMarker);
|
|
|
|
public GuiTrimPanel(GuiReplayEditor gui) {
|
|
this.gui = gui;
|
|
|
|
setLayout(new VerticalLayout().setSpacing(10));
|
|
|
|
Function<Marker, String> toString = m -> {
|
|
if (m == NO_MARKER) {
|
|
return I18n.format("replaymod.gui.editor.trim.marker");
|
|
} else {
|
|
return ofNullable(m.getName()).orElse(I18n.format("replaymod.gui.ingame.unnamedmarker"))
|
|
+ " (" + Utils.convertSecondsToShortString(m.getTime() / 1000) + ")";
|
|
}
|
|
};
|
|
startMarker.setToString(toString).setMinSize(new Dimension(100, 20)).onSelection(i ->
|
|
onSelectedMarkerChanged(startMarker, startHour, startMin, startSec, startMilli));
|
|
endMarker.setToString(toString).setMinSize(new Dimension(100, 20)).onSelection(i ->
|
|
onSelectedMarkerChanged(endMarker, endHour, endMin, endSec, endMilli));
|
|
|
|
File[] files = null;
|
|
try {
|
|
File folder = gui.getMod().getReplayFolder();
|
|
files = folder.listFiles((FileFilter) new SuffixFileFilter(".mcpr", IOCase.INSENSITIVE));
|
|
} catch (IOException e) {
|
|
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(e, "Listing available replays"), gui.backButton::onClick);
|
|
}
|
|
if (files == null) {
|
|
LOGGER.warn("Replay file list is null, has the replay folder been deleted?");
|
|
files = new File[0];
|
|
} else {
|
|
LOGGER.debug("Found {} replays in the replay folder", files.length);
|
|
}
|
|
if (files.length == 0) {
|
|
inputReplays.setValues(NO_REPLAY);
|
|
} else {
|
|
inputReplays.setValues(files);
|
|
}
|
|
|
|
updateSelectedReplay();
|
|
updateReadyState();
|
|
|
|
gui.saveButton.onClick(() -> {
|
|
// Read start and end times
|
|
int start = ((startHour.getInteger() * 60 + startMin.getInteger()) * 60 + startSec.getInteger()) * 1000 + startMilli.getInteger();
|
|
int end = ((endHour.getInteger() * 60 + endMin.getInteger()) * 60 + endSec.getInteger()) * 1000 + endMilli.getInteger();
|
|
// Configure offset of change timestamp filter
|
|
ChangeTimestampFilter ctf = new ChangeTimestampFilter();
|
|
JsonObject config = new JsonObject();
|
|
config.addProperty("offset", -start);
|
|
ctf.init(null, config);
|
|
// Pass filters to save dialog
|
|
gui.save(inputReplays.getSelectedValue(),
|
|
new PacketStream.FilterInfo(new SquashFilter(), -1, start),
|
|
new PacketStream.FilterInfo(ctf, start, end),
|
|
new PacketStream.FilterInfo(new RemoveFilter(), end, -1)
|
|
);
|
|
});
|
|
}
|
|
|
|
private void onSelectedMarkerChanged(GuiDropdownMenu<Marker> dropdown, GuiNumberField hour, GuiNumberField min,
|
|
GuiNumberField sec, GuiNumberField milli) {
|
|
Marker marker = dropdown.getSelectedValue();
|
|
if (marker != NO_MARKER) {
|
|
int time = marker.getTime();
|
|
setTime(time, hour, min, sec, milli);
|
|
}
|
|
}
|
|
|
|
private void setTime(int time, GuiNumberField hour, GuiNumberField min,
|
|
GuiNumberField sec, GuiNumberField milli) {
|
|
milli.setValue(time % 1000); time /= 1000;
|
|
sec.setValue(time % 60); time /= 60;
|
|
min.setValue(time % 60); time /= 60;
|
|
hour.setValue(time);
|
|
}
|
|
|
|
private void updateSelectedReplay() {
|
|
File file = inputReplays.getSelectedValue();
|
|
// Load markers and meta data from replay file
|
|
ReplayMetaData metaData;
|
|
Set<Marker> markers;
|
|
if (file == NO_REPLAY) {
|
|
metaData = new ReplayMetaData();
|
|
markers = Collections.emptySet();
|
|
} else {
|
|
try (ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), file)) {
|
|
metaData = replayFile.getMetaData();
|
|
markers = replayFile.getMarkers().or(Collections.emptySet());
|
|
LOGGER.debug("Loaded {} markers from replay {}", markers.size(), file);
|
|
} catch (Exception e) {
|
|
Utils.error(LOGGER, gui, CrashReport.makeCrashReport(e, "Reading markers from replay"), null);
|
|
metaData = new ReplayMetaData();
|
|
markers = Collections.emptySet();
|
|
}
|
|
}
|
|
|
|
// Sort and add initial "Select Event Marker" element
|
|
List<Marker> markerList = new ArrayList<>(markers);
|
|
markerList.sort(Comparator.comparing(Marker::getTime));
|
|
markerList.add(0, NO_MARKER);
|
|
|
|
// Set marker dropdown values
|
|
Marker[] markerArray = markerList.stream().toArray(Marker[]::new);
|
|
startMarker.setValues(markerArray).setSelected(0);
|
|
endMarker.setValues(markerArray).setSelected(0);
|
|
|
|
// Set start and end time values
|
|
setTime(0, startHour, startMin, startSec, startMilli);
|
|
setTime(metaData.getDuration(), endHour, endMin, endSec, endMilli);
|
|
}
|
|
|
|
private void updateReadyState() {
|
|
gui.saveButton.setEnabled(inputReplays.getSelectedValue() != NO_REPLAY);
|
|
}
|
|
}
|