Move cache folders into central (hidden) location (closes #343)

This commit is contained in:
Jonas Herzig
2020-11-05 16:59:08 +01:00
parent 3ce10d4855
commit 76bec31cd8
9 changed files with 86 additions and 37 deletions

View File

@@ -1,5 +1,6 @@
package com.replaymod.core;
import com.google.common.net.PercentEscaper;
import com.replaymod.compat.ReplayModCompat;
import com.replaymod.core.gui.GuiBackgroundProcesses;
import com.replaymod.core.gui.GuiReplaySettings;
@@ -11,6 +12,8 @@ import com.replaymod.extras.ReplayModExtras;
import com.replaymod.recording.ReplayModRecording;
import com.replaymod.render.ReplayModRender;
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.protocol.ProtocolVersion;
import com.replaymod.replaystudio.util.I18n;
@@ -88,13 +91,16 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -239,6 +245,36 @@ public class ReplayMod implements
return Files.createDirectories(getReplayFolder().resolve("recording"));
}
/**
* Folder in which replay cache files are stored.
* Distinct from the recording folder cause people kept confusing them with recordings.
*/
public Path getCacheFolder() throws IOException {
String str = getSettingsRegistry().get(Setting.CACHE_PATH);
Path path = getMinecraft().runDirectory.toPath().resolve(str);
Files.createDirectories(path);
try {
Files.setAttribute(path, "dos:hidden", true);
} catch (UnsupportedOperationException ignored) {
}
return path;
}
private static final PercentEscaper CACHE_FILE_NAME_ENCODER = new PercentEscaper("-_ ", false);
public Path getCachePathForReplay(Path replay) throws IOException {
Path replayFolder = getReplayFolder();
Path cacheFolder = getCacheFolder();
Path relative = replayFolder.toAbsolutePath().relativize(replay.toAbsolutePath());
return cacheFolder.resolve(CACHE_FILE_NAME_ENCODER.escape(relative.toString()));
}
public Path getReplayPathForCache(Path cache) throws IOException {
String relative = URLDecoder.decode(cache.getFileName().toString(), "UTF-8");
Path replayFolder = getReplayFolder();
return replayFolder.resolve(relative);
}
public static final DirectoryResourcePack jGuiResourcePack;
public static final String JGUI_RESOURCE_PACK_NAME = "replaymod_jgui";
static { // Note: even preInit is too late and we'd have to issue another resource reload
@@ -362,6 +398,23 @@ public class ReplayMod implements
runPostStartup(() -> {
final long DAYS = 24 * 60 * 60 * 1000;
// Cleanup any cache folders still remaining in the recording folder (we once used to put them there)
try {
Files.walkFileTree(getReplayFolder(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
String name = dir.getFileName().toString();
if (name.endsWith(".mcpr.cache")) {
FileUtils.deleteDirectory(dir.toFile());
return FileVisitResult.SKIP_SUBTREE;
}
return super.preVisitDirectory(dir, attrs);
}
});
} catch (IOException e) {
e.printStackTrace();
}
// Cleanup raw folder content three weeks after creation (these are pretty valuable for debugging)
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getRawReplayFolder())) {
for (Path path : paths) {
@@ -388,11 +441,10 @@ public class ReplayMod implements
}
// Cleanup cache folders 7 days after last modification or when its replay is gone
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getReplayFolder())) {
try (DirectoryStream<Path> paths = Files.newDirectoryStream(getCacheFolder())) {
for (Path path : paths) {
String name = path.getFileName().toString();
if (name.endsWith(".mcpr.cache") && Files.isDirectory(path)) {
Path replay = path.resolveSibling(FilenameUtils.getBaseName(name));
if (Files.isDirectory(path)) {
Path replay = getReplayPathForCache(path);
long lastModified = Files.getLastModifiedTime(path).toMillis();
if (lastModified + 7 * DAYS < System.currentTimeMillis() || !Files.exists(replay)) {
FileUtils.deleteDirectory(path.toFile());
@@ -720,4 +772,17 @@ public class ReplayMod implements
return new ReplayStudio().isCompatible(fileFormatVersion, protocolVersion, MCVer.getProtocolVersion());
}
}
public ReplayFile openReplay(Path path) throws IOException {
return openReplay(path, path);
}
public ReplayFile openReplay(Path input, Path output) throws IOException {
return new ZipReplayFile(
new ReplayStudio(),
input != null ? input.toFile() : null,
output.toFile(),
getCachePathForReplay(output).toFile()
);
}
}

View File

@@ -3,6 +3,7 @@ package com.replaymod.core;
public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
public static final Setting<Boolean> NOTIFICATIONS = make("notifications", "notifications", true);
public static final Setting<String> RECORDING_PATH = advanced("recordingPath", null, "./replay_recordings/");
public static final Setting<String> CACHE_PATH = advanced("cachePath", null, "./.replay_cache/");
private static <T> Setting<T> make(String key, String displayName, T defaultValue) {
return new Setting<>("core", key, displayName, defaultValue);

View File

@@ -9,8 +9,6 @@ import com.replaymod.replaystudio.io.ReplayInputStream;
import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScreen;
@@ -110,8 +108,7 @@ public class RestoreReplayGui extends AbstractGuiScreen<RestoreReplayGui> {
}
private void tryRecover(Consumer<Float> progress) throws IOException {
ReplayStudio studio = new ReplayStudio();
ReplayFile replayFile = new ZipReplayFile(studio, null, file);
ReplayFile replayFile = ReplayMod.instance.openReplay(file.toPath());
// Commit all not-yet-committed files into the main zip file.
// If we don't do this, then re-writing packet data below can actually overwrite uncommitted packet data!
replayFile.save();

View File

@@ -5,8 +5,7 @@ import com.replaymod.core.utils.Utils;
import com.replaymod.editor.ReplayModEditor;
import com.replaymod.replay.gui.overlay.GuiMarkerTimeline;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.replay.ReplayFile;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
@@ -61,7 +60,7 @@ public class GuiEditReplay extends AbstractGuiPopup<GuiEditReplay> {
super(container);
this.inputPath = inputPath;
try (ZipReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), inputPath.toFile())) {
try (ReplayFile replayFile = ReplayMod.instance.openReplay(inputPath)) {
markers = replayFile.getMarkers().or(HashSet::new);
timeline = new EditTimeline(new HashSet<>(markers), markers -> this.markers = markers);
timeline.setSize(300, 20)
@@ -148,7 +147,7 @@ public class GuiEditReplay extends AbstractGuiPopup<GuiEditReplay> {
ProgressPopup progressPopup = new ProgressPopup(this);
new Thread(() -> {
try (ZipReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), inputPath.toFile())) {
try (ReplayFile replayFile = ReplayMod.instance.openReplay(inputPath)) {
replayFile.writeMarkers(markers);
replayFile.save();
} catch (IOException e) {

View File

@@ -3,7 +3,6 @@ package com.replaymod.editor.gui;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.versions.MCVer;
import com.replaymod.replaystudio.PacketData;
import com.replaymod.replaystudio.Studio;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.filter.SquashFilter;
import com.replaymod.replaystudio.filter.StreamFilter;
@@ -12,14 +11,11 @@ import com.replaymod.replaystudio.io.ReplayOutputStream;
import com.replaymod.replaystudio.protocol.PacketTypeRegistry;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.stream.IteratorStream;
import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
import com.replaymod.replaystudio.util.Utils;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -52,7 +48,7 @@ public class MarkerProcessor {
public static final String MARKER_NAME_SPLIT = "_RM_SPLIT";
private static boolean hasWork(Path path) throws IOException {
try (ZipReplayFile inputReplayFile = new ZipReplayFile(new ReplayStudio(), path.toFile())) {
try (ReplayFile inputReplayFile = ReplayMod.instance.openReplay(path)) {
return inputReplayFile.getMarkers().or(HashSet::new).stream().anyMatch(m -> m.getName() != null && m.getName().startsWith("_RM_"));
}
}
@@ -109,9 +105,10 @@ public class MarkerProcessor {
}
public static List<Pair<Path, ReplayMetaData>> apply(Path path, Consumer<Float> progress) throws IOException {
ReplayMod mod = ReplayMod.instance;
if (!hasWork(path)) {
ReplayMetaData metaData;
try (ZipReplayFile inputReplayFile = new ZipReplayFile(new ReplayStudio(), path.toFile())) {
try (ReplayFile inputReplayFile = mod.openReplay(path)) {
metaData = inputReplayFile.getMetaData();
}
return Collections.singletonList(new Pair<>(path, metaData));
@@ -121,9 +118,7 @@ public class MarkerProcessor {
int splitCounter = 0;
PacketTypeRegistry registry = MCVer.getPacketTypeRegistry(true);
Studio studio = new ReplayStudio();
SquashFilter squashFilter = new SquashFilter();
squashFilter.init(studio, null);
List<Pair<Path, ReplayMetaData>> outputPaths = new ArrayList<>();
@@ -135,7 +130,7 @@ public class MarkerProcessor {
Files.createDirectories(inputPath.getParent());
Files.move(path, inputPath);
try (ZipReplayFile inputReplayFile = new ZipReplayFile(studio, inputPath.toFile())) {
try (ReplayFile inputReplayFile = mod.openReplay(inputPath)) {
List<Marker> markers = inputReplayFile.getMarkers().or(HashSet::new)
.stream().sorted(Comparator.comparing(Marker::getTime)).collect(Collectors.toList());
Iterator<Marker> markerIterator = markers.iterator();
@@ -152,8 +147,7 @@ public class MarkerProcessor {
while (nextPacket != null && outputFileSuffixes.hasNext()) {
Path outputPath = path.resolveSibling(replayName + outputFileSuffixes.next() + ".mcpr");
File outputFile = outputPath.toFile();
try (ZipReplayFile outputReplayFile = new ZipReplayFile(studio, null, outputFile)) {
try (ReplayFile outputReplayFile = mod.openReplay(null, outputPath)) {
long duration = 0;
Set<Marker> outputMarkers = new HashSet<>();
ReplayMetaData metaData = inputReplayFile.getMetaData();

View File

@@ -12,8 +12,6 @@ import com.replaymod.recording.mixin.NetworkManagerAccessor;
import com.replaymod.recording.packet.PacketListener;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import io.netty.channel.Channel;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ServerInfo;
@@ -123,7 +121,7 @@ public class ConnectionEventHandler {
String name = sdf.format(Calendar.getInstance().getTime());
Path outputPath = core.getRecordingFolder().resolve(Utils.replayNameToFileName(name));
ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), outputPath.toFile());
ReplayFile replayFile = core.openReplay(outputPath);
replayFile.writeModInfo(ModCompat.getInstalledNetworkMods());

View File

@@ -13,8 +13,7 @@ import com.replaymod.replay.ReplayHandler;
import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.ReplaySender;
import com.replaymod.replaystudio.pathing.path.Timeline;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.us.myles.ViaVersion.api.Pair;
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
@@ -216,9 +215,9 @@ public class GuiRenderQueue extends AbstractGuiPopup<GuiRenderQueue> implements
LOGGER.info("Opening replay {} for {} render jobs", next.getKey(), next.getValue().size());
ReplayHandler replayHandler;
ZipReplayFile replayFile = null;
ReplayFile replayFile = null;
try {
replayFile = new ZipReplayFile(new ReplayStudio(), next.getKey());
replayFile = mod.getCore().openReplay(next.getKey().toPath());
replayHandler = mod.startReplay(replayFile, true, false);
} catch (IOException e) {
Utils.error(LOGGER, container, CrashReport.create(e, "Opening replay"), () -> {});

View File

@@ -20,8 +20,6 @@ import com.replaymod.replay.gui.screen.GuiModCompatWarning;
import com.replaymod.replay.handler.GuiHandler;
import com.replaymod.replaystudio.data.Marker;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding;
import org.apache.logging.log4j.LogManager;
@@ -163,7 +161,7 @@ public class ReplayModReplay implements Module {
}
public void startReplay(File file) throws IOException {
startReplay(new ZipReplayFile(new ReplayStudio(), file));
startReplay(core.openReplay(file.toPath()));
}
public void startReplay(ReplayFile replayFile) throws IOException {

View File

@@ -22,8 +22,6 @@ import com.replaymod.replay.ReplayModReplay;
import com.replaymod.replay.Setting;
import com.replaymod.replaystudio.replay.ReplayFile;
import com.replaymod.replaystudio.replay.ReplayMetaData;
import com.replaymod.replaystudio.replay.ZipReplayFile;
import com.replaymod.replaystudio.studio.ReplayStudio;
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
@@ -389,7 +387,7 @@ public class GuiReplayViewer extends GuiScreen {
Arrays.sort(files, Comparator.<File>comparingLong(f -> lastModified.computeIfAbsent(f, File::lastModified)).reversed());
for (final File file : files) {
if (Thread.interrupted()) break;
try (ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), file)) {
try (ReplayFile replayFile = ReplayMod.instance.openReplay(file.toPath())) {
final Image thumb = Optional.ofNullable(replayFile.getThumbBytes().orNull()).flatMap(stream -> {
try (InputStream in = stream) {
return Optional.of(Image.read(in));