Persist render queue in replay file (closes #317)

This commit is contained in:
Jonas Herzig
2020-08-29 21:21:34 +02:00
parent 4a6c0acc8b
commit 9211fb524c
2 changed files with 109 additions and 5 deletions

View File

@@ -1,9 +1,24 @@
package com.replaymod.render; package com.replaymod.render;
import com.google.common.base.Optional;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.replaymod.core.Module; import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod; import com.replaymod.core.ReplayMod;
import com.replaymod.core.utils.Utils;
import com.replaymod.render.utils.RenderJob; import com.replaymod.render.utils.RenderJob;
import com.replaymod.replay.ReplayHandler;
import com.replaymod.replay.events.ReplayClosedCallback; import com.replaymod.replay.events.ReplayClosedCallback;
import com.replaymod.replay.events.ReplayOpenedCallback;
import com.replaymod.replaystudio.pathing.PathingRegistry;
import com.replaymod.replaystudio.pathing.path.Timeline;
import com.replaymod.replaystudio.pathing.serialize.TimelineSerialization;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.simplepathing.SPTimeline;
import de.johni0702.minecraft.gui.container.VanillaGuiScreen;
import de.johni0702.minecraft.gui.utils.EventRegistrations; import de.johni0702.minecraft.gui.utils.EventRegistrations;
import net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashException; import net.minecraft.util.crash.CrashException;
@@ -13,12 +28,16 @@ import org.apache.logging.log4j.Logger;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static com.replaymod.core.versions.MCVer.*;
public class ReplayModRender extends EventRegistrations implements Module { public class ReplayModRender extends EventRegistrations implements Module {
{ instance = this; } { instance = this; }
public static ReplayModRender instance; public static ReplayModRender instance;
@@ -27,6 +46,7 @@ public class ReplayModRender extends EventRegistrations implements Module {
public static Logger LOGGER = LogManager.getLogger(); public static Logger LOGGER = LogManager.getLogger();
private ReplayFile replayFile;
private final List<RenderJob> renderQueue = new ArrayList<>(); private final List<RenderJob> renderQueue = new ArrayList<>();
public ReplayModRender(ReplayMod core) { public ReplayModRender(ReplayMod core) {
@@ -41,8 +61,6 @@ public class ReplayModRender extends EventRegistrations implements Module {
@Override @Override
public void initClient() { public void initClient() {
on(ReplayClosedCallback.EVENT, replayHandler -> renderQueue.clear());
register(); register();
} }
@@ -64,4 +82,87 @@ public class ReplayModRender extends EventRegistrations implements Module {
public List<RenderJob> getRenderQueue() { public List<RenderJob> getRenderQueue() {
return renderQueue; return renderQueue;
} }
{ on(ReplayOpenedCallback.EVENT, this::onReplayOpened); }
private void onReplayOpened(ReplayHandler replayHandler) {
replayFile = replayHandler.getReplayFile();
try {
renderQueue.addAll(doLoadRenderQueue(replayFile));
} catch (IOException e) {
throw new CrashException(CrashReport.create(e, "Reading timeline"));
}
}
{ on(ReplayClosedCallback.EVENT, replayHandler -> onReplayClosed()); }
private void onReplayClosed() {
renderQueue.clear();
replayFile = null;
}
private static List<RenderJob> doLoadRenderQueue(ReplayFile replayFile) throws IOException {
synchronized (replayFile) {
Optional<InputStream> optIn = replayFile.get("renderQueue.json");
if (!optIn.isPresent()) {
return new ArrayList<>();
}
try (InputStream in = optIn.get();
InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
return new GsonBuilder()
.registerTypeAdapter(Timeline.class, new TimelineTypeAdapter())
.create()
.fromJson(reader, new TypeToken<List<RenderJob>>(){}.getType());
}
}
}
private static void doSaveRenderQueue(ReplayFile replayFile, List<RenderJob> renderQueue) throws IOException {
synchronized (replayFile) {
try (OutputStream out = replayFile.write("renderQueue.json");
OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
new GsonBuilder()
.registerTypeAdapter(Timeline.class, new TimelineTypeAdapter())
.create()
.toJson(renderQueue, writer);
}
}
}
public void saveRenderQueue() {
try {
doSaveRenderQueue(replayFile, renderQueue);
} catch (IOException e) {
e.printStackTrace();
VanillaGuiScreen screen = VanillaGuiScreen.setup(getCore().getMinecraft().currentScreen);
CrashReport report = CrashReport.create(e, "Reading timeline");
Utils.error(LOGGER, screen, report, () -> {});
}
}
private static class TimelineTypeAdapter extends TypeAdapter<Timeline> {
private final TimelineSerialization serialization;
public TimelineTypeAdapter(TimelineSerialization serialization) {
this.serialization = serialization;
}
public TimelineTypeAdapter(PathingRegistry registry) {
this(new TimelineSerialization(registry, null));
}
public TimelineTypeAdapter() {
// TODO need to somehow get rid of the reliance on simplepathing
this(new SPTimeline());
}
@Override
public void write(JsonWriter out, Timeline value) throws IOException {
out.value(serialization.serialize(Collections.singletonMap("", value)));
}
@Override
public Timeline read(JsonReader in) throws IOException {
return serialization.deserialize(in.nextString()).get("");
}
}
} }

View File

@@ -99,7 +99,8 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
}).addElements(null, title, list, buttonPanel); }).addElements(null, title, list, buttonPanel);
} }
private final List<RenderJob> jobs = ReplayModRender.instance.getRenderQueue(); private final ReplayModRender mod = ReplayModRender.instance;
private final List<RenderJob> jobs = mod.getRenderQueue();
public GuiRenderQueue(AbstractGuiScreen<?> container, ReplayHandler replayHandler, Supplier<Timeline> timelineSupplier) { public GuiRenderQueue(AbstractGuiScreen<?> container, ReplayHandler replayHandler, Supplier<Timeline> timelineSupplier) {
super(container); super(container);
@@ -131,6 +132,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
} }
selectedEntries.clear(); selectedEntries.clear();
updateButtons(); updateButtons();
mod.saveRenderQueue();
}); });
renderButton.onClick(() -> { renderButton.onClick(() -> {
@@ -214,6 +216,7 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
jobs.add(newJob); jobs.add(newJob);
list.getListPanel().addElements(null, new Entry(newJob)); list.getListPanel().addElements(null, new Entry(newJob));
updateButtons(); updateButtons();
mod.saveRenderQueue();
// Need to close the inner popup before we can open the outer one // Need to close the inner popup before we can open the outer one
close(); close();