Record into separate folder so replays only show once fully saved
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
package com.replaymod.core;
|
package com.replaymod.core;
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.replaymod.compat.ReplayModCompat;
|
import com.replaymod.compat.ReplayModCompat;
|
||||||
import com.replaymod.core.gui.GuiBackgroundProcesses;
|
import com.replaymod.core.gui.GuiBackgroundProcesses;
|
||||||
import com.replaymod.core.gui.GuiReplaySettings;
|
import com.replaymod.core.gui.GuiReplaySettings;
|
||||||
@@ -27,6 +26,7 @@ import net.minecraft.text.LiteralText;
|
|||||||
import net.minecraft.text.TranslatableText;
|
import net.minecraft.text.TranslatableText;
|
||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
import net.minecraft.util.crash.CrashException;
|
import net.minecraft.util.crash.CrashException;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
//#if MC>=11400
|
//#if MC>=11400
|
||||||
@@ -89,6 +89,9 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.DirectoryStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -216,11 +219,24 @@ public class ReplayMod implements
|
|||||||
return settingsRegistry;
|
return settingsRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getReplayFolder() throws IOException {
|
public Path getReplayFolder() throws IOException {
|
||||||
String path = getSettingsRegistry().get(Setting.RECORDING_PATH);
|
String str = getSettingsRegistry().get(Setting.RECORDING_PATH);
|
||||||
File folder = new File(path.startsWith("./") ? getMinecraft().runDirectory : null, path);
|
return Files.createDirectories(getMinecraft().runDirectory.toPath().resolve(str));
|
||||||
FileUtils.forceMkdir(folder);
|
}
|
||||||
return folder;
|
|
||||||
|
/**
|
||||||
|
* Folder into which replay backups are saved before the MarkerProcessor is unleashed.
|
||||||
|
*/
|
||||||
|
public Path getRawReplayFolder() throws IOException {
|
||||||
|
return Files.createDirectories(getReplayFolder().resolve("raw"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Folder into which replays are recorded.
|
||||||
|
* Distinct from the main folder, so they cannot be opened while they are still saving.
|
||||||
|
*/
|
||||||
|
public Path getRecordingFolder() throws IOException {
|
||||||
|
return Files.createDirectories(getReplayFolder().resolve("recording"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final DirectoryResourcePack jGuiResourcePack;
|
public static final DirectoryResourcePack jGuiResourcePack;
|
||||||
@@ -347,30 +363,39 @@ public class ReplayMod implements
|
|||||||
final long DAYS = 24 * 60 * 60 * 1000;
|
final long DAYS = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
// Cleanup raw folder content three weeks after creation (these are pretty valuable for debugging)
|
// Cleanup raw folder content three weeks after creation (these are pretty valuable for debugging)
|
||||||
try {
|
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getRawReplayFolder())) {
|
||||||
File[] files = new File(getReplayFolder(), "raw").listFiles();
|
for (Path path : paths) {
|
||||||
if (files != null) {
|
if (Files.getLastModifiedTime(path).toMillis() + 21 * DAYS < System.currentTimeMillis()) {
|
||||||
for (File file : files) {
|
Files.delete(path);
|
||||||
if (file.lastModified() + 21 * DAYS < System.currentTimeMillis()) {
|
|
||||||
FileUtils.forceDelete(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup cache folders 7 days after last modification or when its replay is gone
|
// Move anything which is still in the recording folder into the regular replay folder
|
||||||
try {
|
// so it can be opened and/or recovered
|
||||||
File[] files = getReplayFolder().listFiles();
|
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getRecordingFolder())) {
|
||||||
if (files != null) {
|
for (Path path : paths) {
|
||||||
for (File file : files) {
|
Path destination = getReplayFolder().resolve(path.getFileName());
|
||||||
String name = file.getName();
|
if (Files.exists(destination)) {
|
||||||
if (file.isDirectory() && name.endsWith(".mcpr.cache")) {
|
continue; // better play it save
|
||||||
File replay = new File(getReplayFolder(), name.substring(0, name.length() - ".cache".length()));
|
|
||||||
if (file.lastModified() + 7 * DAYS < System.currentTimeMillis() || !replay.exists()) {
|
|
||||||
FileUtils.deleteDirectory(file);
|
|
||||||
}
|
}
|
||||||
|
Files.move(path, destination);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup cache folders 7 days after last modification or when its replay is gone
|
||||||
|
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getReplayFolder())) {
|
||||||
|
for (Path path : paths) {
|
||||||
|
String name = path.getFileName().toString();
|
||||||
|
if (name.endsWith(".mcpr.cache") && Files.isDirectory(path)) {
|
||||||
|
Path replay = path.resolveSibling(FilenameUtils.getBaseName(name));
|
||||||
|
long lastModified = Files.getLastModifiedTime(path).toMillis();
|
||||||
|
if (lastModified + 7 * DAYS < System.currentTimeMillis() || !Files.exists(replay)) {
|
||||||
|
FileUtils.deleteDirectory(path.toFile());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,14 +404,13 @@ public class ReplayMod implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup deleted corrupted replays
|
// Cleanup deleted corrupted replays
|
||||||
try {
|
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getReplayFolder())) {
|
||||||
File[] files = getReplayFolder().listFiles();
|
for (Path path : paths) {
|
||||||
if (files != null) {
|
String name = path.getFileName().toString();
|
||||||
for (File file : files) {
|
if (name.endsWith(".mcpr.del") && Files.isDirectory(path)) {
|
||||||
if (file.isDirectory() && file.getName().endsWith(".mcpr.del")) {
|
long lastModified = Files.getLastModifiedTime(path).toMillis();
|
||||||
if (file.lastModified() + 2 * DAYS < System.currentTimeMillis()) {
|
if (lastModified + 2 * DAYS < System.currentTimeMillis()) {
|
||||||
FileUtils.deleteDirectory(file);
|
FileUtils.deleteDirectory(path.toFile());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,14 +419,12 @@ public class ReplayMod implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restore corrupted replays
|
// Restore corrupted replays
|
||||||
try {
|
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getReplayFolder())) {
|
||||||
File[] files = getReplayFolder().listFiles();
|
for (Path path : paths) {
|
||||||
if (files != null) {
|
String name = path.getFileName().toString();
|
||||||
for (File file : files) {
|
if (name.endsWith(".mcpr.tmp") && Files.isDirectory(path)) {
|
||||||
if (file.isDirectory() && file.getName().endsWith(".mcpr.tmp")) {
|
Path original = path.resolveSibling(FilenameUtils.getBaseName(name));
|
||||||
File origFile = new File(file.getParentFile(), Files.getNameWithoutExtension(file.getName()));
|
new RestoreReplayGui(this, GuiScreen.wrap(mc.currentScreen), original.toFile()).display();
|
||||||
new RestoreReplayGui(this, GuiScreen.wrap(mc.currentScreen), origFile).display();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.replaymod.editor.gui;
|
package com.replaymod.editor.gui;
|
||||||
|
|
||||||
|
import com.replaymod.core.ReplayMod;
|
||||||
import com.replaymod.core.versions.MCVer;
|
import com.replaymod.core.versions.MCVer;
|
||||||
import com.replaymod.replaystudio.PacketData;
|
import com.replaymod.replaystudio.PacketData;
|
||||||
import com.replaymod.replaystudio.Studio;
|
import com.replaymod.replaystudio.Studio;
|
||||||
@@ -126,7 +127,8 @@ public class MarkerProcessor {
|
|||||||
|
|
||||||
List<Pair<Path, ReplayMetaData>> outputPaths = new ArrayList<>();
|
List<Pair<Path, ReplayMetaData>> outputPaths = new ArrayList<>();
|
||||||
|
|
||||||
Path inputPath = path.resolveSibling("raw").resolve(path.getFileName());
|
Path rawFolder = ReplayMod.instance.getRawReplayFolder();
|
||||||
|
Path inputPath = rawFolder.resolve(path.getFileName());
|
||||||
for (int i = 1; Files.exists(inputPath); i++) {
|
for (int i = 1; Files.exists(inputPath); i++) {
|
||||||
inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr");
|
inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,13 +109,7 @@ public class GuiSavingReplay {
|
|||||||
.addElements(null, textField, clearButton);
|
.addElements(null, textField, clearButton);
|
||||||
panel.addElements(new VerticalLayout.Data(0.5), row);
|
panel.addElements(new VerticalLayout.Data(0.5), row);
|
||||||
|
|
||||||
apply.add(() -> {
|
apply.add(() -> applyOutput(path, textField.getText()));
|
||||||
String newName = textField.getText();
|
|
||||||
if (newName.equals(originalName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
applyOutput(path, newName);
|
|
||||||
});
|
|
||||||
|
|
||||||
return textField;
|
return textField;
|
||||||
}
|
}
|
||||||
@@ -151,12 +145,12 @@ public class GuiSavingReplay {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path newPath = path.resolveSibling(Utils.replayNameToFileName(newName));
|
|
||||||
if (Files.exists(newPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Path replaysFolder = core.getReplayFolder();
|
||||||
|
Path newPath = replaysFolder.resolve(Utils.replayNameToFileName(newName));
|
||||||
|
for (int i = 1; Files.exists(newPath); i++) {
|
||||||
|
newPath = replaysFolder.resolve(Utils.replayNameToFileName(newName + " (" + i + ")"));
|
||||||
|
}
|
||||||
Files.move(path, newPath);
|
Files.move(path, newPath);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Renaming replay file:", e);
|
logger.error("Renaming replay file:", e);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import net.minecraft.world.World;
|
|||||||
//#endif
|
//#endif
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
import java.io.File;
|
import java.nio.file.Path;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|
||||||
@@ -121,11 +121,9 @@ public class ConnectionEventHandler {
|
|||||||
autoStart = true;
|
autoStart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
File folder = core.getReplayFolder();
|
|
||||||
|
|
||||||
String name = sdf.format(Calendar.getInstance().getTime());
|
String name = sdf.format(Calendar.getInstance().getTime());
|
||||||
File currentFile = new File(folder, Utils.replayNameToFileName(name));
|
Path outputPath = core.getRecordingFolder().resolve(Utils.replayNameToFileName(name));
|
||||||
ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), currentFile);
|
ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), outputPath.toFile());
|
||||||
|
|
||||||
replayFile.writeModInfo(ModCompat.getInstalledNetworkMods());
|
replayFile.writeModInfo(ModCompat.getInstalledNetworkMods());
|
||||||
|
|
||||||
@@ -135,7 +133,7 @@ public class ConnectionEventHandler {
|
|||||||
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
|
metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion());
|
||||||
metaData.setDate(System.currentTimeMillis());
|
metaData.setDate(System.currentTimeMillis());
|
||||||
metaData.setMcVersion(ReplayMod.getMinecraftVersion());
|
metaData.setMcVersion(ReplayMod.getMinecraftVersion());
|
||||||
packetListener = new PacketListener(core, currentFile.toPath(), replayFile, metaData);
|
packetListener = new PacketListener(core, outputPath, replayFile, metaData);
|
||||||
Channel channel = ((NetworkManagerAccessor) networkManager).getChannel();
|
Channel channel = ((NetworkManagerAccessor) networkManager).getChannel();
|
||||||
channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);
|
channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener);
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
File folder = mod.getCore().getReplayFolder();
|
File folder = mod.getCore().getReplayFolder().toFile();
|
||||||
|
|
||||||
MCVer.openFile(folder);
|
MCVer.openFile(folder);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -245,7 +245,7 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
this.mod = mod;
|
this.mod = mod;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
list.setFolder(mod.getCore().getReplayFolder());
|
list.setFolder(mod.getCore().getReplayFolder().toFile());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CrashException(CrashReport.create(e, "Getting replay folder"));
|
throw new CrashException(CrashReport.create(e, "Getting replay folder"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user