From be282adacf67837f04041db8cc45797d9c81bc22 Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Wed, 15 Apr 2020 21:02:35 +0200 Subject: [PATCH] Initial version of multiple compression format system. Some more testing still required --- build.gradle | 5 +- gradle.properties | 2 +- .../textile_backup/ConfigHandler.java | 26 ++- .../commands/CleanupCommand.java | 2 - .../textile_backup/core/BackupHelper.java | 205 ++++++++++-------- .../textile_backup/core/Compressor.java | 69 ------ .../textile_backup/core/MakeBackupThread.java | 32 ++- .../compressors/GenericTarCompressor.java | 66 ++++++ .../core/{ => compressors}/ZipCompressor.java | 37 ++-- .../mixin/MinecraftServerMixin.java | 9 +- 10 files changed, 269 insertions(+), 184 deletions(-) delete mode 100644 src/main/java/net/szum123321/textile_backup/core/Compressor.java create mode 100644 src/main/java/net/szum123321/textile_backup/core/compressors/GenericTarCompressor.java rename src/main/java/net/szum123321/textile_backup/core/{ => compressors}/ZipCompressor.java (64%) diff --git a/build.gradle b/build.gradle index 3607f22..ab628e5 100644 --- a/build.gradle +++ b/build.gradle @@ -33,8 +33,9 @@ dependencies { include "io.github.cottonmc.cotton:cotton-logging:1.0.0-rc.4" include "io.github.cottonmc.cotton:cotton-config:1.0.0-rc.7" - include "org.apache.commons:commons-compress:1.9" - include "org.apache.commons:commons-io:1.3.2" + modCompile "org.apache.commons:commons-compress:1.20" + include "org.apache.commons:commons-compress:1.20" + //include "org.apache.commons:commons-io:1.3.2" // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. diff --git a/gradle.properties b/gradle.properties index 6d2e753..5e339a3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,6 +9,6 @@ loader_version=0.7.9+build.190 fabric_version=0.5.7+build.314-1.16 # Mod Properties - mod_version = 1.1.1-1.15 + mod_version = 1.2.0-1.15 maven_group = net.szum123321 archives_base_name = textile_backup \ No newline at end of file diff --git a/src/main/java/net/szum123321/textile_backup/ConfigHandler.java b/src/main/java/net/szum123321/textile_backup/ConfigHandler.java index e37e4e7..70fde08 100644 --- a/src/main/java/net/szum123321/textile_backup/ConfigHandler.java +++ b/src/main/java/net/szum123321/textile_backup/ConfigHandler.java @@ -54,9 +54,16 @@ public class ConfigHandler { @Comment("\nMaximum size of backup folder in kilo bytes. \n") public int maxSize = 0; - @Comment("\nCompression level \n0 - 9\n") + @Comment("\nCompression level \n0 - 9\n Only available for zip compression.\n") public int compression = 1; + @Comment(value = "\nAvailable formats are:\n" + + "ZIP - normal zip archive using standard deflate compression\n" + + "BZIP2 - tar.bz2 archive using bzip2 compression\n" + + "GIZP - tar.gz using gzip compression\n" + + "LZ4 - tar.lz using lz4 compression\n") + public ArchiveFormat format = ArchiveFormat.ZIP; + @Comment("\nPrint info to game out\n") public boolean log = true; @@ -74,4 +81,21 @@ public class ConfigHandler { @Comment("\nFormat of date&time used to name backup files.\n") public String dateTimeFormat = "dd.MM.yyyy_HH-mm-ss"; + + public enum ArchiveFormat { + ZIP(".zip"), + BZIP2(".tar.bz2"), + GZIP(".tar.gz"), + LZ4(".tar.lz4"); + + private String extension; + + private ArchiveFormat(String extension){ + this.extension = extension; + } + + public String getExtension() { + return extension; + } + }; } diff --git a/src/main/java/net/szum123321/textile_backup/commands/CleanupCommand.java b/src/main/java/net/szum123321/textile_backup/commands/CleanupCommand.java index e4af2a2..cfe39bf 100644 --- a/src/main/java/net/szum123321/textile_backup/commands/CleanupCommand.java +++ b/src/main/java/net/szum123321/textile_backup/commands/CleanupCommand.java @@ -21,7 +21,6 @@ package net.szum123321.textile_backup.commands; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; import net.minecraft.world.dimension.DimensionType; import net.szum123321.textile_backup.core.BackupHelper; @@ -33,7 +32,6 @@ public class CleanupCommand { private static int execute(ServerCommandSource source){ BackupHelper.executeFileLimit(source, source.getMinecraftServer().getWorld(DimensionType.OVERWORLD).getLevelProperties().getLevelName()); - source.sendFeedback(new LiteralText("Done"), false); return 1; } diff --git a/src/main/java/net/szum123321/textile_backup/core/BackupHelper.java b/src/main/java/net/szum123321/textile_backup/core/BackupHelper.java index 1a33e5c..4f2bdf6 100644 --- a/src/main/java/net/szum123321/textile_backup/core/BackupHelper.java +++ b/src/main/java/net/szum123321/textile_backup/core/BackupHelper.java @@ -21,124 +21,155 @@ package net.szum123321.textile_backup.core; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; +import net.szum123321.textile_backup.ConfigHandler; import net.szum123321.textile_backup.TextileBackup; import org.apache.commons.io.FileUtils; import java.io.File; -import java.io.FileFilter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.FileTime; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Arrays; +import java.util.Objects; public class BackupHelper { - public static void create(MinecraftServer server, ServerCommandSource ctx, boolean save, String comment) { - LocalDateTime now = LocalDateTime.now(); + public static Thread create(MinecraftServer server, ServerCommandSource ctx, boolean save, String comment) { + LocalDateTime now = LocalDateTime.now(); - StringBuilder builder = new StringBuilder(); - builder.append("Backup started by: "); + StringBuilder builder = new StringBuilder(); + builder.append("Backup started by: "); - if( ctx != null ) - builder.append(ctx.getName()); - else - builder.append("SERVER"); + if (ctx != null) + builder.append(ctx.getName()); + else + builder.append("SERVER"); - builder.append(" on: "); - builder.append(Utilities.getDateTimeFormatter().format(now)); + builder.append(" on: "); + builder.append(Utilities.getDateTimeFormatter().format(now)); - Utilities.log(builder.toString(), null); + Utilities.log(builder.toString(), null); - Utilities.log("Saving server...", ctx); + Utilities.log("Saving server...", ctx); - if(save) - server.save(true, false, false); + if (save) + server.save(true, true, false); - Thread thread = new Thread(new MakeBackupThread(server, ctx, comment)); + Thread thread = new Thread(new MakeBackupThread(server, ctx, comment)); - thread.start(); - } + thread.start(); - public static void executeFileLimit(ServerCommandSource ctx, String worldName){ - File root = getBackupRootPath(worldName); + return thread; + } - FileFilter filter = f -> f.getName().endsWith("zip"); + public static void executeFileLimit(ServerCommandSource ctx, String worldName) { + File root = getBackupRootPath(worldName); - if(root.isDirectory() && root.exists()){ - if(TextileBackup.config.maxAge > 0){ - LocalDateTime now = LocalDateTime.now(); + if (root.isDirectory() && root.exists()) { + if (TextileBackup.config.maxAge > 0) { + LocalDateTime now = LocalDateTime.now(); - Arrays.stream(root.listFiles()).forEach(f ->{ - if(f.exists() && f.isFile()){ - LocalDateTime creationTime; + Arrays.stream(root.listFiles()).filter(f -> f.exists() && f.isFile()).forEach(f -> { + LocalDateTime creationTime = null; - try { - creationTime = LocalDateTime.from( - Utilities.getDateTimeFormatter().parse( - f.getName().split(".zip")[0].split("#")[0] - ) - ); - }catch(Exception e){ - creationTime = LocalDateTime.from( - Utilities.getBackupDateTimeFormatter().parse( - f.getName().split(".zip")[0].split("#")[0] - ) - ); + try { + try { + FileTime ct = (FileTime) Files.getAttribute(f.toPath(), "creationTime"); - } + creationTime = LocalDateTime.ofInstant(ct.toInstant(), ZoneOffset.UTC); + } catch (IOException ignored) { + try { + creationTime = LocalDateTime.from( + Utilities.getDateTimeFormatter().parse( + f.getName().split(Objects.requireNonNull(getFileExtension(f)))[0].split("#")[0] + ) + ); + } catch (Exception ignored2) { + creationTime = LocalDateTime.from( + Utilities.getBackupDateTimeFormatter().parse( + f.getName().split(Objects.requireNonNull(getFileExtension(f)))[0].split("#")[0] + ) + ); + } + } - if(now.toEpochSecond(ZoneOffset.UTC) - creationTime.toEpochSecond(ZoneOffset.UTC) > TextileBackup.config.maxAge) { - Utilities.log("Deleting: " + f.getName(), ctx); - f.delete(); - } - } - }); - } + if (now.toEpochSecond(ZoneOffset.UTC) - creationTime.toEpochSecond(ZoneOffset.UTC) > TextileBackup.config.maxAge) { + Utilities.log("Deleting: " + f.getName(), ctx); + f.delete(); + } + } catch (NullPointerException ignored3) { + } + }); + } - if(TextileBackup.config.backupsToKeep > 0 && root.listFiles().length > TextileBackup.config.backupsToKeep){ - int var1 = root.listFiles().length - TextileBackup.config.backupsToKeep; + if (TextileBackup.config.backupsToKeep > 0 && root.listFiles().length > TextileBackup.config.backupsToKeep) { + int var1 = root.listFiles().length - TextileBackup.config.backupsToKeep; - File[] files = root.listFiles(filter); - assert files != null; + File[] files = root.listFiles(); + assert files != null; - Arrays.sort(files); + Arrays.sort(files); - for(int i = 0; i < var1; i++) { - Utilities.log("Deleting: " + files[i].getName(), ctx); - files[i].delete(); - } - } + for (int i = 0; i < var1; i++) { + Utilities.log("Deleting: " + files[i].getName(), ctx); + files[i].delete(); + } + } - if(TextileBackup.config.maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize){ - Arrays.stream(root.listFiles()).sorted().forEach(e -> { - if(FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize){ - Utilities.log("Deleting: " + e.getName(), ctx); - e.delete(); - } - }); - } - } - } + if (TextileBackup.config.maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize) { + Arrays.stream(root.listFiles()).filter(File::isFile).sorted().forEach(e -> { + if (FileUtils.sizeOfDirectory(root) / 1024 > TextileBackup.config.maxSize) { + Utilities.log("Deleting: " + e.getName(), ctx); + e.delete(); + } + }); + } + } + } - public static File getBackupRootPath(String worldName){ - File path = new File(TextileBackup.config.path); + private static String getFileExtension(File f) { + System.out.println(f.getName()); + String[] parts = f.getName().split("\\."); + System.out.println(parts.length); - if(TextileBackup.config.perWorldBackup) - path = path.toPath().resolve(worldName).toFile(); + switch (parts[parts.length - 1]) { + case "zip": + return ConfigHandler.ArchiveFormat.ZIP.getExtension(); + case "bz2": + return ConfigHandler.ArchiveFormat.BZIP2.getExtension(); + case "gz": + return ConfigHandler.ArchiveFormat.GZIP.getExtension(); + case "lz4": + return ConfigHandler.ArchiveFormat.LZ4.getExtension(); - if(!path.exists()){ - try{ - path.mkdirs(); - }catch(Exception e){ - TextileBackup.logger.error(e.getMessage()); + default: + return null; + } + } - return FabricLoader - .getInstance() - .getGameDirectory() - .toPath() - .resolve(TextileBackup.config.path) - .toFile(); - } - } - return path; - } -} + public static File getBackupRootPath(String worldName) { + File path = new File(TextileBackup.config.path); + + if (TextileBackup.config.perWorldBackup) + path = path.toPath().resolve(worldName).toFile(); + + if (!path.exists()) { + try { + path.mkdirs(); + } catch (Exception e) { + TextileBackup.logger.error(e.getMessage()); + + return FabricLoader + .getInstance() + .getGameDirectory() + .toPath() + .resolve(TextileBackup.config.path) + .toFile(); + } + } + + return path; + } +} \ No newline at end of file diff --git a/src/main/java/net/szum123321/textile_backup/core/Compressor.java b/src/main/java/net/szum123321/textile_backup/core/Compressor.java deleted file mode 100644 index 663e54b..0000000 --- a/src/main/java/net/szum123321/textile_backup/core/Compressor.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - A simple backup mod for Fabric - Copyright (C) 2020 Szum123321 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -package net.szum123321.textile_backup.core; - -import net.minecraft.server.command.ServerCommandSource; -import net.szum123321.textile_backup.TextileBackup; -import org.apache.commons.compress.utils.IOUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.time.LocalDateTime; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class Compressor { - public static void createArchive(File in, File out, ServerCommandSource ctx){ - Utilities.log("Starting compression...", ctx); - - try { - File input = in.getCanonicalFile(); - - ZipOutputStream arc = new ZipOutputStream(new FileOutputStream(out)); - - arc.setLevel(TextileBackup.config.compression); - arc.setComment("Created on: " + Utilities.getDateTimeFormatter().format(LocalDateTime.now())); - - int rootPathLength = input.toString().length() + 1; - - Files.walk(input.toPath()).filter(path -> !path.equals(input.toPath()) && path.toFile().isFile() && !TextileBackup.config.fileBlacklist.contains(path.toString().substring(rootPathLength))).forEach(path -> { - try{ - File file = path.toAbsolutePath().toFile(); - - ZipEntry entry = new ZipEntry(file.getAbsolutePath().substring(rootPathLength)); - arc.putNextEntry(entry); - entry.setSize(file.length()); - IOUtils.copy(new FileInputStream(file), arc); - arc.closeEntry(); - }catch (IOException e){ - TextileBackup.logger.error(e.getMessage()); - } - }); - - arc.close(); - } catch (IOException e) { - TextileBackup.logger.error(e.getMessage()); - } - - Utilities.log("Compression finished", ctx); - } -} diff --git a/src/main/java/net/szum123321/textile_backup/core/MakeBackupThread.java b/src/main/java/net/szum123321/textile_backup/core/MakeBackupThread.java index 8d40756..f3454ba 100644 --- a/src/main/java/net/szum123321/textile_backup/core/MakeBackupThread.java +++ b/src/main/java/net/szum123321/textile_backup/core/MakeBackupThread.java @@ -21,6 +21,12 @@ package net.szum123321.textile_backup.core; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.world.dimension.DimensionType; +import net.szum123321.textile_backup.TextileBackup; +import net.szum123321.textile_backup.core.compressors.GenericTarCompressor; +import net.szum123321.textile_backup.core.compressors.ZipCompressor; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; +import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorOutputStream; import java.io.File; import java.io.IOException; @@ -59,7 +65,29 @@ public class MakeBackupThread implements Runnable { return; } - ZipCompressor.createArchive(world, outFile, ctx); + switch (TextileBackup.config.format) { + case ZIP: + ZipCompressor.createArchive(world, outFile, ctx); + break; + + case BZIP2: + GenericTarCompressor.createArchive(world, outFile, BZip2CompressorOutputStream.class, ctx); + break; + + case GZIP: + GenericTarCompressor.createArchive(world, outFile, GzipCompressorOutputStream.class, ctx); + break; + + case LZ4: + GenericTarCompressor.createArchive(world, outFile, FramedLZ4CompressorOutputStream.class, ctx); + break; + + default: + Utilities.log("Error! No compression format specified! using default compressor!", ctx); + ZipCompressor.createArchive(world, outFile, ctx); + break; + } + BackupHelper.executeFileLimit(ctx, server.getWorld(DimensionType.OVERWORLD).getLevelProperties().getLevelName()); @@ -69,6 +97,6 @@ public class MakeBackupThread implements Runnable { private String getFileName(){ LocalDateTime now = LocalDateTime.now(); - return Utilities.getDateTimeFormatter().format(now) + (comment != null ? "#" + comment.replace("#", ""): "") + ".zip"; + return Utilities.getDateTimeFormatter().format(now) + (comment != null ? "#" + comment.replace("#", ""): "") + TextileBackup.config.format.getExtension(); } } diff --git a/src/main/java/net/szum123321/textile_backup/core/compressors/GenericTarCompressor.java b/src/main/java/net/szum123321/textile_backup/core/compressors/GenericTarCompressor.java new file mode 100644 index 0000000..a115dbd --- /dev/null +++ b/src/main/java/net/szum123321/textile_backup/core/compressors/GenericTarCompressor.java @@ -0,0 +1,66 @@ +package net.szum123321.textile_backup.core.compressors; + +import net.minecraft.server.command.ServerCommandSource; +import net.szum123321.textile_backup.TextileBackup; +import net.szum123321.textile_backup.core.Utilities; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.compressors.CompressorOutputStream; +import org.apache.commons.compress.utils.IOUtils; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; + +public class GenericTarCompressor { + public static void createArchive(File in, File out, Class CompressorStreamClass, ServerCommandSource ctx) { + Utilities.log("Starting compression...", ctx); + + try (FileOutputStream outStream = new FileOutputStream(out); + BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outStream); + CompressorOutputStream lz4Stream = CompressorStreamClass.getDeclaredConstructor(OutputStream.class).newInstance(bufferedOutputStream);// CompressorStreamClass.getConstructor().newInstance(bufferedOutputStream); + TarArchiveOutputStream arc = new TarArchiveOutputStream(lz4Stream)) { + + System.out.println(lz4Stream.getClass().toString()); + + arc.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + arc.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); + + File input = in.getCanonicalFile(); + int rootPathLength = input.toString().length() + 1; + + Files.walk(input.toPath()).filter( + path -> !path.equals(input.toPath()) && + path.toFile().isFile() && + !TextileBackup.config.fileBlacklist.contains(path.toString().substring(rootPathLength)) + ).forEach(path -> { + File file = path.toAbsolutePath().toFile(); + + try (FileInputStream fin = new FileInputStream(file); + BufferedInputStream bfin = new BufferedInputStream(fin)){ + TarArchiveEntry entry = new TarArchiveEntry(file, file.getAbsolutePath().substring(rootPathLength)); + + entry.setSize(file.length()); + arc.putArchiveEntry(entry); + IOUtils.copy(bfin, arc); + + arc.closeArchiveEntry(); + } catch (IOException e) { + TextileBackup.logger.error(e.getMessage()); + } + }); + } catch (IOException e) { + TextileBackup.logger.error(e.getMessage()); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + + Utilities.log("Compression finished", ctx); + } +} diff --git a/src/main/java/net/szum123321/textile_backup/core/ZipCompressor.java b/src/main/java/net/szum123321/textile_backup/core/compressors/ZipCompressor.java similarity index 64% rename from src/main/java/net/szum123321/textile_backup/core/ZipCompressor.java rename to src/main/java/net/szum123321/textile_backup/core/compressors/ZipCompressor.java index a4f2ded..522e04c 100644 --- a/src/main/java/net/szum123321/textile_backup/core/ZipCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/compressors/ZipCompressor.java @@ -16,29 +16,29 @@ along with this program. If not, see . */ -package net.szum123321.textile_backup.core; +package net.szum123321.textile_backup.core.compressors; import net.minecraft.server.command.ServerCommandSource; import net.szum123321.textile_backup.TextileBackup; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; +import net.szum123321.textile_backup.core.Utilities; +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; import java.time.LocalDateTime; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; public class ZipCompressor { public static void createArchive(File in, File out, ServerCommandSource ctx){ Utilities.log("Starting compression...", ctx); - try (ZipOutputStream arc = new ZipOutputStream(new FileOutputStream(out))){ + try (FileOutputStream fileOutputStream = new FileOutputStream(out); + BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); + ZipArchiveOutputStream arc = new ZipArchiveOutputStream(bufferedOutputStream)){ + + arc.setMethod(ZipArchiveOutputStream.DEFLATED); arc.setLevel(TextileBackup.config.compression); arc.setComment("Created on: " + Utilities.getDateTimeFormatter().format(LocalDateTime.now())); @@ -46,19 +46,20 @@ public class ZipCompressor { int rootPathLength = input.toString().length() + 1; Files.walk(input.toPath()).filter(path -> !path.equals(input.toPath()) && path.toFile().isFile() && !TextileBackup.config.fileBlacklist.contains(path.toString().substring(rootPathLength))).forEach(path -> { - try{ - File file = path.toAbsolutePath().toFile(); + File file = path.toAbsolutePath().toFile(); + try (FileInputStream fstream = new FileInputStream(file)) { + ZipArchiveEntry entry = new ZipArchiveEntry(file, file.getAbsolutePath().substring(rootPathLength)); + arc.putArchiveEntry(entry); - ZipEntry entry = new ZipEntry(file.getAbsolutePath().substring(rootPathLength)); - arc.putNextEntry(entry); - entry.setSize(file.length()); - IOUtils.copy(new FileInputStream(file), arc); - arc.closeEntry(); + IOUtils.copy(fstream, arc); + + arc.closeArchiveEntry(); }catch (IOException e){ TextileBackup.logger.error(e.getMessage()); } }); + arc.finish(); } catch (IOException e) { TextileBackup.logger.error(e.getMessage()); } diff --git a/src/main/java/net/szum123321/textile_backup/mixin/MinecraftServerMixin.java b/src/main/java/net/szum123321/textile_backup/mixin/MinecraftServerMixin.java index 86cb0a7..6c48fe5 100644 --- a/src/main/java/net/szum123321/textile_backup/mixin/MinecraftServerMixin.java +++ b/src/main/java/net/szum123321/textile_backup/mixin/MinecraftServerMixin.java @@ -52,7 +52,12 @@ public abstract class MinecraftServerMixin { @Inject(method = "shutdown", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/server/MinecraftServer;save(ZZZ)Z")) public void onShutdown(CallbackInfo ci){ - if(TextileBackup.config.shutdownBackup) - BackupHelper.create((MinecraftServer)(Object)this, null, false, null); + if(TextileBackup.config.shutdownBackup) { + try { + BackupHelper.create((MinecraftServer) (Object) this, null, false, "shutdown").join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } } }