diff --git a/src/main/java/org/mcphackers/mcp/MCPPaths.java b/src/main/java/org/mcphackers/mcp/MCPPaths.java index b92a00d..6c85ba7 100644 --- a/src/main/java/org/mcphackers/mcp/MCPPaths.java +++ b/src/main/java/org/mcphackers/mcp/MCPPaths.java @@ -41,6 +41,7 @@ public class MCPPaths { public static final String VERSION = CONF + "version.json"; public static final String PATCH = "patches/%s.patch"; + public static final String PATCHDIR = "patches/%s"; public static final String UPDATE_JAR = "update.jar"; diff --git a/src/main/java/org/mcphackers/mcp/tasks/TaskApplyPatch.java b/src/main/java/org/mcphackers/mcp/tasks/TaskApplyPatch.java index 7036c4e..3607846 100644 --- a/src/main/java/org/mcphackers/mcp/tasks/TaskApplyPatch.java +++ b/src/main/java/org/mcphackers/mcp/tasks/TaskApplyPatch.java @@ -1,12 +1,16 @@ package org.mcphackers.mcp.tasks; -import static org.mcphackers.mcp.MCPPaths.PATCH; +import static org.mcphackers.mcp.MCPPaths.PATCHDIR; import static org.mcphackers.mcp.MCPPaths.SOURCE; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import codechicken.diffpatch.PatchOperation; import codechicken.diffpatch.util.PatchMode; @@ -14,6 +18,7 @@ import org.mcphackers.mcp.MCPPaths; public class TaskApplyPatch extends TaskStaged { + private int complete = 0; public TaskApplyPatch(Side side, MCP instance) { super(side, instance); @@ -23,23 +28,44 @@ public TaskApplyPatch(Side side, MCP instance) { protected Stage[] setStages() { return new Stage[] { stage(getLocalizedStage("patching"), () -> { - final Path patchesPath = MCPPaths.get(mcp, PATCH, side); + final Path patchesRoot = MCPPaths.get(mcp, PATCHDIR, side); final Path srcPath = MCPPaths.get(mcp, SOURCE, side); - patch(this, srcPath, srcPath, patchesPath); + + try (Stream walker = Files.walk(patchesRoot)) { + List files = walker.filter((path) -> path.toFile().isFile() && path.toString().endsWith(".patch")).collect(Collectors.toList()); + int total = files.size(); + + // We can't use parallel streams here, since some patches may modify multiple + // files, and that would cause conflicts. + + for (Path path : files) { + patch(this, srcPath, srcPath, path); + complete++; + setProgress((int) ((double) complete / (double) total * 100)); + } + } + + // final Path patchesPath = MCPPaths.get(mcp, PATCH, side); + // final Path srcPath = MCPPaths.get(mcp, SOURCE, side); + // patch(this, srcPath, srcPath, patchesPath); }) }; } public static void patch(Task task, Path base, Path out, Path patches) throws IOException { ByteArrayOutputStream logger = new ByteArrayOutputStream(); + PatchOperation patchOperation = PatchOperation.builder() .basePath(base) .patchesPath(patches) .outputPath(out) .mode(PatchMode.OFFSET) .build(); + boolean success = patchOperation.doPatch(); + patchOperation.getSummary().print(new PrintStream(logger), false); + if (!success) { task.addMessage(logger.toString(), Task.INFO); task.addMessage("Patching failed!", Task.ERROR); diff --git a/src/main/java/org/mcphackers/mcp/tasks/TaskDownloadSpoutPatch.java b/src/main/java/org/mcphackers/mcp/tasks/TaskDownloadSpoutPatch.java index 165e0e9..52345d3 100644 --- a/src/main/java/org/mcphackers/mcp/tasks/TaskDownloadSpoutPatch.java +++ b/src/main/java/org/mcphackers/mcp/tasks/TaskDownloadSpoutPatch.java @@ -1,20 +1,22 @@ package org.mcphackers.mcp.tasks; import static org.mcphackers.mcp.MCPPaths.PATCH; -import static org.mcphackers.mcp.MCPPaths.SOURCE; +import static org.mcphackers.mcp.MCPPaths.PATCHDIR; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.nio.file.Path; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; -import codechicken.diffpatch.PatchOperation; -import codechicken.diffpatch.util.PatchMode; import org.mcphackers.mcp.MCP; import org.mcphackers.mcp.MCPPaths; import org.mcphackers.mcp.tools.FileUtil; public class TaskDownloadSpoutPatch extends TaskStaged { + private static final String PATCH_ZIP_URL = "https://github.com/RedstoneWizard08/Grease/archive/refs/heads/main.zip"; + private static final String PATCH_PATH_PREFIX = "Grease-main/patches/"; public TaskDownloadSpoutPatch(Side side, MCP instance) { super(side, instance); @@ -22,13 +24,43 @@ public TaskDownloadSpoutPatch(Side side, MCP instance) { @Override protected Stage[] setStages() { + final Path patchesPath = MCPPaths.get(mcp, PATCHDIR, side); + final Path zipFilePath = patchesPath.resolve("spoutcraft-patches.zip"); + final Path patchFolderPath = patchesPath.resolve("spoutcraft-patches"); + return new Stage[] { - stage(getLocalizedStage("download", "Spoutcraft's patch file"), () -> { - final Path patchesPath = MCPPaths.get(mcp, PATCH, side); - patchesPath.toFile().mkdirs(); - FileUtil.downloadFile("https://raw.githubusercontent.com/ReSpouted/Grease/main/client.patch", patchesPath.resolve("client.patch")); - }) + stage(getLocalizedStage("download", "Spoutcraft's patch file"), () -> { + patchesPath.toFile().mkdirs(); + // FileUtil.downloadFile("https://raw.githubusercontent.com/ReSpouted/Grease/main/client.patch", patchesPath.resolve("client.patch")); + FileUtil.downloadFile(PATCH_ZIP_URL, zipFilePath); + }), + stage(getLocalizedStage("extract", "Spoutcraft's patch file"), () -> { + ZipInputStream zip = new ZipInputStream(new FileInputStream(zipFilePath.toFile())); + ZipEntry entry = zip.getNextEntry(); + byte[] buf = new byte[1024]; + + while (entry != null) { + if (!entry.isDirectory() && entry.getName().endsWith(".patch")) { + Path outputPath = patchFolderPath.resolve(entry.getName().replaceFirst(PATCH_PATH_PREFIX, "")); + + outputPath.getParent().toFile().mkdirs(); + + FileOutputStream fos = new FileOutputStream(outputPath.toFile()); + int len; + + while ((len = zip.read(buf)) > 0) { + fos.write(buf, 0, len); + } + + fos.close(); + } + + entry = zip.getNextEntry(); + } + + zip.closeEntry(); + zip.close(); + }) }; } - } diff --git a/src/main/java/org/mcphackers/mcp/tasks/mode/TaskMode.java b/src/main/java/org/mcphackers/mcp/tasks/mode/TaskMode.java index c312bd7..f019639 100644 --- a/src/main/java/org/mcphackers/mcp/tasks/mode/TaskMode.java +++ b/src/main/java/org/mcphackers/mcp/tasks/mode/TaskMode.java @@ -138,8 +138,10 @@ public class TaskMode { public static TaskMode APPLY_PATCH = new TaskModeBuilder() .setName("applypatch") .setTaskClass(TaskApplyPatch.class) - .setProgressBars(false) - .addRequirement((mcp, side) -> Files.isReadable(MCPPaths.get(mcp, MCPPaths.PATCH, side)) + .setProgressBars(true) + // .addRequirement((mcp, side) -> Files.isReadable(MCPPaths.get(mcp, MCPPaths.PATCH, side)) + // && Files.isReadable(MCPPaths.get(mcp, MCPPaths.SOURCE, side))) + .addRequirement((mcp, side) -> Files.exists(MCPPaths.get(mcp, MCPPaths.PATCHDIR, side)) && Files.isReadable(MCPPaths.get(mcp, MCPPaths.SOURCE, side))) .setParameters(new TaskParameter[]{ TaskParameter.SIDE diff --git a/src/main/resources/lang/en_US.lang b/src/main/resources/lang/en_US.lang index 801ac7d..f236976 100644 --- a/src/main/resources/lang/en_US.lang +++ b/src/main/resources/lang/en_US.lang @@ -76,7 +76,7 @@ task.backupsrc = Backup source task.backupsrc.desc = Pack source files into a zip task.downloadspoutpatch = Download Spoutcraft's patch task.applypatch = Apply patch -task.applypatch.desc = Apply patch from patches directory +task.applypatch.desc = Apply patches from patches directory task.updatemcp = Update RetroMCP task.updatemcp.desc = Check for updates task.noDesc = No description provided