Add render queue
This commit is contained in:
@@ -1,16 +1,22 @@
|
||||
package com.replaymod.render;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.render.utils.RenderJob;
|
||||
import com.replaymod.replay.events.ReplayCloseEvent;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.util.ReportedException;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mod(modid = ReplayModRender.MOD_ID,
|
||||
version = "@MOD_VERSION@",
|
||||
@@ -24,9 +30,10 @@ public class ReplayModRender {
|
||||
|
||||
private ReplayMod core;
|
||||
|
||||
private Logger logger;
|
||||
public static Logger LOGGER;
|
||||
|
||||
private Configuration configuration;
|
||||
private final List<RenderJob> renderQueue = new ArrayList<>();
|
||||
|
||||
public ReplayMod getCore() {
|
||||
return core;
|
||||
@@ -34,13 +41,20 @@ public class ReplayModRender {
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
logger = event.getModLog();
|
||||
LOGGER = event.getModLog();
|
||||
core = ReplayMod.instance;
|
||||
configuration = new Configuration(event.getSuggestedConfigurationFile());
|
||||
|
||||
FMLCommonHandler.instance().bus().register(this);
|
||||
|
||||
core.getSettingsRegistry().register(Setting.class);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onReplayClose(ReplayCloseEvent.Post event) {
|
||||
renderQueue.clear();
|
||||
}
|
||||
|
||||
public File getVideoFolder() {
|
||||
String path = core.getSettingsRegistry().get(Setting.RENDER_PATH);
|
||||
File folder = new File(path.startsWith("./") ? core.getMinecraft().mcDataDir : null, path);
|
||||
@@ -55,4 +69,8 @@ public class ReplayModRender {
|
||||
public Configuration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public List<RenderJob> getRenderQueue() {
|
||||
return renderQueue;
|
||||
}
|
||||
}
|
||||
|
||||
277
src/main/java/com/replaymod/render/gui/GuiRenderQueue.java
Normal file
277
src/main/java/com/replaymod/render/gui/GuiRenderQueue.java
Normal file
@@ -0,0 +1,277 @@
|
||||
package com.replaymod.render.gui;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.replaymod.render.ReplayModRender;
|
||||
import com.replaymod.render.rendering.VideoRenderer;
|
||||
import com.replaymod.render.utils.RenderJob;
|
||||
import com.replaymod.replay.ReplayHandler;
|
||||
import com.replaymod.replaystudio.pathing.path.Timeline;
|
||||
import com.replaymod.replaystudio.util.I18n;
|
||||
import de.johni0702.minecraft.gui.GuiRenderer;
|
||||
import de.johni0702.minecraft.gui.RenderInfo;
|
||||
import de.johni0702.minecraft.gui.container.AbstractGuiClickableContainer;
|
||||
import de.johni0702.minecraft.gui.container.GuiContainer;
|
||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
||||
import de.johni0702.minecraft.gui.container.GuiVerticalList;
|
||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
||||
import de.johni0702.minecraft.gui.element.GuiTextField;
|
||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
||||
import de.johni0702.minecraft.gui.layout.GridLayout;
|
||||
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
||||
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
|
||||
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
||||
import de.johni0702.minecraft.gui.utils.Colors;
|
||||
import net.minecraft.client.gui.GuiErrorScreen;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.util.ReportedException;
|
||||
import org.lwjgl.util.Dimension;
|
||||
import org.lwjgl.util.ReadableDimension;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.replaymod.render.ReplayModRender.LOGGER;
|
||||
|
||||
public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> {
|
||||
private final GuiLabel title = new GuiLabel().setI18nText("replaymod.gui.renderqueue.title").setColor(Colors.BLACK);
|
||||
private final GuiVerticalList list = new GuiVerticalList().setDrawShadow(true).setDrawSlider(true);
|
||||
private final GuiButton addButton = new GuiButton().setI18nLabel("replaymod.gui.renderqueue.add").setSize(150, 20);
|
||||
private final GuiButton renameButton = new GuiButton().setI18nLabel("replaymod.gui.rename").setSize(73, 20);
|
||||
private final GuiButton removeButton = new GuiButton().setI18nLabel("replaymod.gui.remove").setSize(73, 20);
|
||||
private final GuiButton renderButton = new GuiButton().setI18nLabel("replaymod.gui.render").setSize(150, 20);
|
||||
private final GuiButton closeButton = new GuiButton().setI18nLabel("replaymod.gui.close").setSize(150, 20).onClick(this::close);
|
||||
|
||||
/*
|
||||
|
||||
|---------------------------------|
|
||||
| Add | Render |
|
||||
|---------------------------------|
|
||||
| Rename | Remove | Close |
|
||||
|---------------------------------|
|
||||
|
||||
*/
|
||||
private final GuiPanel buttonPanel = new GuiPanel()
|
||||
.setLayout(new GridLayout().setSpacingX(5).setSpacingY(5).setColumns(2))
|
||||
.addElements(null,
|
||||
addButton,
|
||||
renderButton,
|
||||
new GuiPanel().setLayout(new HorizontalLayout().setSpacing(4)).addElements(null,
|
||||
renameButton, removeButton),
|
||||
closeButton);
|
||||
|
||||
private final GuiContainer container;
|
||||
private Entry selectedEntry;
|
||||
|
||||
{
|
||||
popup.setLayout(new CustomLayout<GuiPanel>() {
|
||||
@Override
|
||||
protected void layout(GuiPanel container, int width, int height) {
|
||||
pos(title, width / 2 - width(title) / 2, 0);
|
||||
pos(list, 0, y(title) + height(title) + 5);
|
||||
pos(buttonPanel, width / 2 - width(buttonPanel) / 2, height - height(buttonPanel));
|
||||
size(list, width, y(buttonPanel) - y(list) - 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
||||
ReadableDimension screenSize = GuiRenderQueue.this.container.getMinSize();
|
||||
return new Dimension(screenSize.getWidth() - 40,
|
||||
screenSize.getHeight() - 20 - buttonPanel.getMinSize().getHeight() - title.getMinSize().getHeight());
|
||||
}
|
||||
}).addElements(null, title, list, buttonPanel);
|
||||
}
|
||||
|
||||
public GuiRenderQueue(GuiContainer container, GuiRenderSettings guiRenderSettings, ReplayHandler replayHandler, Timeline timeline) {
|
||||
super(container);
|
||||
this.container = container;
|
||||
LOGGER.trace("Opening render queue popup");
|
||||
|
||||
setBackgroundColor(Colors.DARK_TRANSPARENT);
|
||||
|
||||
List<RenderJob> queue = ReplayModRender.instance.getRenderQueue();
|
||||
|
||||
for (RenderJob renderJob : queue) {
|
||||
LOGGER.trace("Adding {} to job queue list", renderJob);
|
||||
list.getListPanel().addElements(null, new Entry(renderJob));
|
||||
}
|
||||
|
||||
addButton.onClick(() -> {
|
||||
LOGGER.trace("Add button clicked");
|
||||
// Open popup
|
||||
GuiYesNoPopup popup = GuiYesNoPopup.open(container)
|
||||
.setYesI18nLabel("replaymod.gui.add").setNoI18nLabel("replaymod.gui.cancel");
|
||||
popup.getInfo().setLayout(new HorizontalLayout(HorizontalLayout.Alignment.CENTER).setSpacing(5));
|
||||
// Add content
|
||||
GuiLabel label = new GuiLabel().setI18nText("replaymod.gui.renderqueue.jobname").setColor(Colors.BLACK);
|
||||
GuiTextField nameField = new GuiTextField().setSize(150, 20).setFocused(true);
|
||||
popup.getInfo().addElements(new HorizontalLayout.Data(0.5), label, nameField);
|
||||
// Disable "Yes" button while name is empty
|
||||
nameField.onTextChanged(old -> popup.getYesButton().setEnabled(!nameField.getText().isEmpty())).onEnter(() -> {
|
||||
if (popup.getYesButton().isEnabled()) {
|
||||
popup.getYesButton().onClick();
|
||||
}
|
||||
});
|
||||
popup.getYesButton().setDisabled();
|
||||
// Register callback
|
||||
Futures.addCallback(popup.getFuture(), new FutureCallback<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Boolean result) {
|
||||
if (result == Boolean.TRUE) {
|
||||
RenderJob newJob = new RenderJob();
|
||||
newJob.setName(nameField.getText());
|
||||
newJob.setSettings(guiRenderSettings.save(false));
|
||||
newJob.setTimeline(timeline);
|
||||
LOGGER.trace("Adding new job: {}", newJob);
|
||||
queue.add(newJob);
|
||||
list.getListPanel().addElements(null, new Entry(newJob));
|
||||
} else {
|
||||
LOGGER.trace("Adding cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
LOGGER.error("Add Job popup:", t);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (guiRenderSettings != null) {
|
||||
addButton.setEnabled(guiRenderSettings.renderButton.isEnabled());
|
||||
}
|
||||
|
||||
renameButton.onClick(() -> {
|
||||
LOGGER.trace("Rename button clicked for {}", selectedEntry.job);
|
||||
// Open popup
|
||||
GuiYesNoPopup popup = GuiYesNoPopup.open(container)
|
||||
.setYesI18nLabel("replaymod.gui.rename").setNoI18nLabel("replaymod.gui.cancel");
|
||||
popup.getInfo().setLayout(new HorizontalLayout(HorizontalLayout.Alignment.CENTER).setSpacing(5));
|
||||
// Add content
|
||||
GuiLabel label = new GuiLabel().setI18nText("replaymod.gui.renderqueue.jobname").setColor(Colors.BLACK);
|
||||
GuiTextField nameField = new GuiTextField().setSize(150, 20).setFocused(true)
|
||||
.setText(selectedEntry.job.getName());
|
||||
popup.getInfo().addElements(new HorizontalLayout.Data(0.5), label, nameField);
|
||||
// Disable "Yes" button while name is empty
|
||||
nameField.onTextChanged(old -> popup.getYesButton().setEnabled(!nameField.getText().isEmpty())).onEnter(() -> {
|
||||
if (popup.getYesButton().isEnabled()) {
|
||||
popup.getYesButton().onClick();
|
||||
}
|
||||
});
|
||||
// Register callback
|
||||
Futures.addCallback(popup.getFuture(), new FutureCallback<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Boolean result) {
|
||||
if (result == Boolean.TRUE) {
|
||||
LOGGER.trace("Renaming {} to \"{}\"", selectedEntry.job, nameField.getText());
|
||||
selectedEntry.setName(nameField.getText());
|
||||
} else {
|
||||
LOGGER.trace("Renaming cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
LOGGER.error("Rename Job popup:", t);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
removeButton.onClick(() -> {
|
||||
LOGGER.trace("Remove button clicked for {}", selectedEntry.job);
|
||||
list.getListPanel().removeElement(selectedEntry);
|
||||
queue.remove(selectedEntry.job);
|
||||
selectedEntry = null;
|
||||
updateButtons();
|
||||
});
|
||||
|
||||
renderButton.onClick(() -> {
|
||||
LOGGER.trace("Render button clicked");
|
||||
// Close all GUIs (so settings in GuiRenderSettings are saved)
|
||||
getMinecraft().displayGuiScreen(null);
|
||||
// Start rendering
|
||||
for (RenderJob renderJob : queue) {
|
||||
LOGGER.info("Starting render job {}", renderJob);
|
||||
try {
|
||||
VideoRenderer videoRenderer = new VideoRenderer(renderJob.getSettings(), replayHandler, renderJob.getTimeline());
|
||||
videoRenderer.renderVideo();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Rendering video:", e);
|
||||
GuiErrorScreen errorScreen = new GuiErrorScreen(I18n.format("replaymod.gui.rendering.error.title"),
|
||||
I18n.format("replaymod.gui.rendering.error.message"));
|
||||
getMinecraft().displayGuiScreen(errorScreen);
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
CrashReport crashReport = CrashReport.makeCrashReport(t, "Rendering video");
|
||||
throw new ReportedException(crashReport);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
super.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiRenderQueue getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void updateButtons() {
|
||||
renameButton.setEnabled(selectedEntry != null);
|
||||
removeButton.setEnabled(selectedEntry != null);
|
||||
renderButton.setEnabled(!list.getListPanel().getChildren().isEmpty());
|
||||
}
|
||||
|
||||
public class Entry extends AbstractGuiClickableContainer<Entry> {
|
||||
public final GuiLabel label = new GuiLabel(this);
|
||||
public final RenderJob job;
|
||||
|
||||
public Entry(RenderJob job) {
|
||||
this.job = job;
|
||||
|
||||
setLayout(new CustomLayout<Entry>() {
|
||||
@Override
|
||||
protected void layout(Entry container, int width, int height) {
|
||||
pos(label, 5, height / 2 - height(label) / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
||||
return new Dimension(buttonPanel.calcMinSize().getWidth(), 16);
|
||||
}
|
||||
});
|
||||
label.setText(job.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick() {
|
||||
selectedEntry = this;
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
|
||||
if (selectedEntry == this) {
|
||||
renderer.drawRect(0, 0, size.getWidth(), size.getHeight(), Colors.BLACK);
|
||||
renderer.drawRect(0, 0, 2, size.getHeight(), Colors.WHITE);
|
||||
}
|
||||
super.draw(renderer, size, renderInfo);
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
job.setName(name);
|
||||
label.setText(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Entry getThis() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,6 +185,12 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
||||
|
||||
|
||||
public final GuiPanel buttonPanel = new GuiPanel(contentPanel).setLayout(new HorizontalLayout().setSpacing(4));
|
||||
public final GuiButton queueButton = new GuiButton(buttonPanel).onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new GuiRenderQueue(GuiRenderSettings.this, GuiRenderSettings.this, replayHandler, timeline).open();
|
||||
}
|
||||
}).setSize(100, 20).setI18nLabel("replaymod.gui.renderqueue.open");
|
||||
public final GuiButton renderButton = new GuiButton(buttonPanel).onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -204,13 +210,13 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
||||
throw new ReportedException(crashReport);
|
||||
}
|
||||
}
|
||||
}).setSize(148, 20).setI18nLabel("replaymod.gui.render");
|
||||
}).setSize(100, 20).setI18nLabel("replaymod.gui.render");
|
||||
public final GuiButton cancelButton = new GuiButton(buttonPanel).onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getMinecraft().displayGuiScreen(null);
|
||||
}
|
||||
}).setSize(148, 20).setI18nLabel("replaymod.gui.cancel");
|
||||
}).setSize(100, 20).setI18nLabel("replaymod.gui.cancel");
|
||||
|
||||
{
|
||||
setBackground(Background.NONE);
|
||||
@@ -437,4 +443,8 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
||||
return configuration.get("rendersettings", "settings", "{}",
|
||||
"Last state of the render settings GUI. Internal use only.");
|
||||
}
|
||||
|
||||
public ReplayHandler getReplayHandler() {
|
||||
return replayHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.replaymod.render.rendering;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.pathing.player.AbstractTimelinePlayer;
|
||||
import com.replaymod.pathing.player.ReplayTimer;
|
||||
import com.replaymod.pathing.properties.TimestampProperty;
|
||||
import com.replaymod.render.RenderSettings;
|
||||
import com.replaymod.render.ReplayModRender;
|
||||
@@ -55,6 +56,7 @@ public class VideoRenderer implements RenderInfo {
|
||||
private boolean debugInfoWasShown;
|
||||
private Map originalSoundLevels;
|
||||
|
||||
private TimelinePlayer timelinePlayer;
|
||||
private Future<Void> timelinePlayerFuture;
|
||||
private ChunkLoadingRenderGlobal chunkLoadingRenderGlobal;
|
||||
|
||||
@@ -174,7 +176,8 @@ public class VideoRenderer implements RenderInfo {
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
timelinePlayerFuture = new TimelinePlayer(replayHandler).start(timeline);
|
||||
timelinePlayer = new TimelinePlayer(replayHandler);
|
||||
timelinePlayerFuture = timelinePlayer.start(timeline);
|
||||
|
||||
if (!OpenGlHelper.isFramebufferEnabled()) {
|
||||
Display.setResizable(false);
|
||||
@@ -229,6 +232,8 @@ public class VideoRenderer implements RenderInfo {
|
||||
if (!timelinePlayerFuture.isDone()) {
|
||||
timelinePlayerFuture.cancel(false);
|
||||
}
|
||||
// Tear down of the timeline player might only happen the next tick after it was cancelled
|
||||
timelinePlayer.onTick(new ReplayTimer.UpdatedEvent());
|
||||
|
||||
if (!OpenGlHelper.isFramebufferEnabled()) {
|
||||
Display.setResizable(true);
|
||||
|
||||
12
src/main/java/com/replaymod/render/utils/RenderJob.java
Normal file
12
src/main/java/com/replaymod/render/utils/RenderJob.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.replaymod.render.utils;
|
||||
|
||||
import com.replaymod.render.RenderSettings;
|
||||
import com.replaymod.replaystudio.pathing.path.Timeline;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RenderJob {
|
||||
private String name;
|
||||
private Timeline timeline;
|
||||
private RenderSettings settings;
|
||||
}
|
||||
@@ -35,13 +35,13 @@ public class ReplayModSimplePathing implements PathingRegistry {
|
||||
|
||||
private ReplayMod core;
|
||||
|
||||
private Logger logger;
|
||||
public static Logger LOGGER;
|
||||
|
||||
private GuiPathing guiPathing;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
logger = event.getModLog();
|
||||
LOGGER = event.getModLog();
|
||||
core = ReplayMod.instance;
|
||||
|
||||
core.getSettingsRegistry().register(Setting.class);
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.replaymod.replaystudio.pathing.path.Path;
|
||||
import com.replaymod.replaystudio.pathing.path.PathSegment;
|
||||
import com.replaymod.replaystudio.pathing.path.Timeline;
|
||||
import com.replaymod.replaystudio.pathing.property.Property;
|
||||
import com.replaymod.replaystudio.pathing.serialize.TimelineSerialization;
|
||||
import com.replaymod.replaystudio.util.EntityPositionTracker;
|
||||
import com.replaymod.replaystudio.util.Location;
|
||||
import com.replaymod.simplepathing.ReplayModSimplePathing;
|
||||
@@ -41,6 +42,7 @@ 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.crash.CrashReport;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
@@ -56,10 +58,14 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.replaymod.core.utils.Utils.error;
|
||||
import static com.replaymod.simplepathing.ReplayModSimplePathing.LOGGER;
|
||||
|
||||
|
||||
/**
|
||||
* Gui plug-in to the GuiReplayOverlay for simple pathing.
|
||||
@@ -91,7 +97,19 @@ public class GuiPathing {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!preparePathsForPlayback()) return;
|
||||
new GuiRenderSettings(replayHandler, mod.getCurrentTimeline()).display();
|
||||
|
||||
// Clone the timeline passed to the settings gui as it may be stored for later rendering in a queue
|
||||
Timeline timeline = mod.getCurrentTimeline();
|
||||
try {
|
||||
TimelineSerialization serialization = new TimelineSerialization(mod, null);
|
||||
String serialized = serialization.serialize(Collections.singletonMap("", timeline));
|
||||
timeline = serialization.deserialize(serialized).get("");
|
||||
} catch (Throwable t) {
|
||||
error(LOGGER, replayHandler.getOverlay(), CrashReport.makeCrashReport(t, "Cloning timeline"), () -> {});
|
||||
return;
|
||||
}
|
||||
|
||||
new GuiRenderSettings(replayHandler, timeline).display();
|
||||
}
|
||||
}).setSize(20, 20).setTexture(ReplayMod.TEXTURE, ReplayMod.TEXTURE_SIZE).setTexturePosH(40, 0)
|
||||
.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.ingame.menu.renderpath"));
|
||||
|
||||
Reference in New Issue
Block a user