From 9211fb524ceadd2fbe499038c3d985b975b24551 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 29 Aug 2020 21:21:34 +0200 Subject: [PATCH] Persist render queue in replay file (closes #317) --- .../com/replaymod/render/ReplayModRender.java | 109 +++++++++++++++++- .../replaymod/render/gui/GuiRenderQueue.java | 5 +- 2 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/replaymod/render/ReplayModRender.java b/src/main/java/com/replaymod/render/ReplayModRender.java index 5c5c46ce..22d5159a 100644 --- a/src/main/java/com/replaymod/render/ReplayModRender.java +++ b/src/main/java/com/replaymod/render/ReplayModRender.java @@ -1,9 +1,24 @@ 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.ReplayMod; +import com.replaymod.core.utils.Utils; import com.replaymod.render.utils.RenderJob; +import com.replaymod.replay.ReplayHandler; 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 net.minecraft.util.crash.CrashReport; import net.minecraft.util.crash.CrashException; @@ -13,12 +28,16 @@ import org.apache.logging.log4j.Logger; import java.io.File; 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.util.ArrayList; +import java.util.Collections; import java.util.List; -import static com.replaymod.core.versions.MCVer.*; - public class ReplayModRender extends EventRegistrations implements Module { { instance = this; } public static ReplayModRender instance; @@ -27,6 +46,7 @@ public class ReplayModRender extends EventRegistrations implements Module { public static Logger LOGGER = LogManager.getLogger(); + private ReplayFile replayFile; private final List renderQueue = new ArrayList<>(); public ReplayModRender(ReplayMod core) { @@ -41,8 +61,6 @@ public class ReplayModRender extends EventRegistrations implements Module { @Override public void initClient() { - on(ReplayClosedCallback.EVENT, replayHandler -> renderQueue.clear()); - register(); } @@ -64,4 +82,87 @@ public class ReplayModRender extends EventRegistrations implements Module { public List getRenderQueue() { 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 doLoadRenderQueue(ReplayFile replayFile) throws IOException { + synchronized (replayFile) { + Optional 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>(){}.getType()); + } + } + } + + private static void doSaveRenderQueue(ReplayFile replayFile, List 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 { + + 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(""); + } + } } diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java index e8067b07..afa997b6 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderQueue.java @@ -99,7 +99,8 @@ public class GuiRenderQueue extends AbstractGuiPopup implements }).addElements(null, title, list, buttonPanel); } - private final List jobs = ReplayModRender.instance.getRenderQueue(); + private final ReplayModRender mod = ReplayModRender.instance; + private final List jobs = mod.getRenderQueue(); public GuiRenderQueue(AbstractGuiScreen container, ReplayHandler replayHandler, Supplier timelineSupplier) { super(container); @@ -131,6 +132,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements } selectedEntries.clear(); updateButtons(); + mod.saveRenderQueue(); }); renderButton.onClick(() -> { @@ -214,6 +216,7 @@ public class GuiRenderQueue extends AbstractGuiPopup implements jobs.add(newJob); list.getListPanel().addElements(null, new Entry(newJob)); updateButtons(); + mod.saveRenderQueue(); // Need to close the inner popup before we can open the outer one close();