From cf21103d3ea40fa883bb5632c52d3c2db80b6ee9 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Tue, 14 Oct 2025 09:36:54 -0600 Subject: [PATCH] Add support for zipped data and resource packs --- mcpacker/ui/runner.py | 9 ++++- mcpacker/write/datapack/metawriter.py | 24 +++--------- mcpacker/write/datapack/metawriter_test.py | 7 ++++ mcpacker/write/datapack/writer.py | 38 ++++-------------- mcpacker/write/datapack/writer_test.py | 7 ++++ mcpacker/write/locator.py | 24 ++++++++++-- mcpacker/write/packmetawriter.py | 30 ++++++++++++++ mcpacker/write/resourcepack/metawriter.py | 11 ++++++ .../write/resourcepack/metawriter_test.py | 7 ++++ mcpacker/write/resourcepack/writer.py | 15 +++++++ mcpacker/write/resourcepack/writer_test.py | 7 ++++ mcpacker/write/zipwriter.py | 39 +++++++++++++++++++ 12 files changed, 164 insertions(+), 54 deletions(-) create mode 100644 mcpacker/write/datapack/metawriter_test.py create mode 100644 mcpacker/write/datapack/writer_test.py create mode 100644 mcpacker/write/packmetawriter.py create mode 100644 mcpacker/write/resourcepack/metawriter.py create mode 100644 mcpacker/write/resourcepack/metawriter_test.py create mode 100644 mcpacker/write/resourcepack/writer.py create mode 100644 mcpacker/write/resourcepack/writer_test.py create mode 100644 mcpacker/write/zipwriter.py diff --git a/mcpacker/ui/runner.py b/mcpacker/ui/runner.py index ccdb1eb..be61861 100644 --- a/mcpacker/ui/runner.py +++ b/mcpacker/ui/runner.py @@ -3,10 +3,12 @@ from mcpacker.format.report.mineralreport import MineralReport from mcpacker.format.report.mobspawnreport import MobSpawnReport from mcpacker.model.modpack import ModPack from mcpacker.write.compositewriter import CompositeWriter -from mcpacker.write.datapack.metawriter import MetaWriter +from mcpacker.write.datapack.metawriter import DataPackMetaWriter from mcpacker.write.datapack.writer import DataPackWriter from mcpacker.write.incontrol.spawnerwriter import SpawnerWriter from mcpacker.write.report.writer import ReportWriter +from mcpacker.write.resourcepack.metawriter import ResourcePackMetaWriter +from mcpacker.write.resourcepack.writer import ResourcePackWriter from mcpacker.write.staticwriter import StaticWriter from pathlib import Path @@ -57,6 +59,9 @@ class Runner: StaticWriter(self.pack, self.outputDir), SpawnerWriter(self.pack, self.outputDir), DataPackWriter(self.pack, self.outputDir, [ - MetaWriter(self.pack, self.outputDir), + DataPackMetaWriter(self.pack, self.outputDir, 48), + ]), + ResourcePackWriter(self.pack, self.outputDir, [ + ResourcePackMetaWriter(self.pack, self.outputDir, 34), ]), ]).write() diff --git a/mcpacker/write/datapack/metawriter.py b/mcpacker/write/datapack/metawriter.py index 2c49c15..6096ba4 100644 --- a/mcpacker/write/datapack/metawriter.py +++ b/mcpacker/write/datapack/metawriter.py @@ -1,25 +1,11 @@ -from mcpacker.model.modpack import ModPack -from mcpacker.write.writer import Writer +from mcpacker.write.packmetawriter import PackMetaWriter from pathlib import Path -import mcpacker.json as json - # Class ############################################################################################ -class MetaWriter(Writer): +class DataPackMetaWriter(PackMetaWriter): - def __init__(self, pack:ModPack, outputDir:Path): - super().__init__(pack, outputDir) - - def doWrite(self): - path = self.locator.dataPack() / "pack.mcmeta" - self.resetOutputFile(path) - - with path.open("w") as file: - file.write(json.dumps({ - "pack": { - "pack_format": 48, - "description": f"auto-generated overrides for {self.pack.name}" - } - }, indent=" ")) + @property + def packRoot(self) -> Path: + return self.locator.dataPack() diff --git a/mcpacker/write/datapack/metawriter_test.py b/mcpacker/write/datapack/metawriter_test.py new file mode 100644 index 0000000..6097f1d --- /dev/null +++ b/mcpacker/write/datapack/metawriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.datapack.metawriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/datapack/writer.py b/mcpacker/write/datapack/writer.py index 01a5166..6f68364 100644 --- a/mcpacker/write/datapack/writer.py +++ b/mcpacker/write/datapack/writer.py @@ -1,37 +1,15 @@ -from collections.abc import Iterable -from mcpacker.model.modpack import ModPack -from mcpacker.write.compositewriter import CompositeWriter -from mcpacker.write.writer import Writer -from mcpacker.write.locator import Locator +from mcpacker.write.zipwriter import ZipWriter from pathlib import Path -from tempfile import TemporaryDirectory -from zipfile import ZipFile -from zipfile import ZIP_DEFLATED - -import mcpacker.json as json -import os # Class ############################################################################################ -class DataPackWriter(CompositeWriter): +class DataPackWriter(ZipWriter): - def doWrite(self): - outputDir = self.locator.outputDir - archivePath = self.locator.dataPacks() / f"{self.pack.name}.jar" + @property + def archiveFile(self) -> Path: + return self.locator.dataPacks() / f"{self.pack.name}.jar" - with TemporaryDirectory() as buildDir: - self.locator.outputDir = Path(buildDir) - for writer in self._writers: - writer.locator.outputDir = self.locator.outputDir - writer.write() - - dataPackPath = self.locator.dataPack() - archivePath.parent.mkdir(exist_ok=True, parents=True) - - with ZipFile(archivePath, "w", ZIP_DEFLATED) as zipFile: - for path in dataPackPath.rglob("*"): - if not path.is_file(): continue - zipFile.write(path, path.relative_to(dataPackPath.parent)) - - self.locator.outputDir = outputDir + @property + def gatherFromDir(self) -> Path: + return self.locator.dataPack() diff --git a/mcpacker/write/datapack/writer_test.py b/mcpacker/write/datapack/writer_test.py new file mode 100644 index 0000000..a376e87 --- /dev/null +++ b/mcpacker/write/datapack/writer_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.datapack.writer + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/locator.py b/mcpacker/write/locator.py index 1de57ae..1125df8 100644 --- a/mcpacker/write/locator.py +++ b/mcpacker/write/locator.py @@ -1,8 +1,6 @@ from mcpacker.model.modpack import ModPack from pathlib import Path -from typing import Protocol -from typing import TypeVar -from typing import TypeAlias +from tempfile import TemporaryDirectory # Class ############################################################################################ @@ -25,6 +23,26 @@ class Locator: self.pack = pack self.outputDir = outputDir + def inTempDir(self): + locator = self + + class Context: + def __init__(self): + self.tempDir = TemporaryDirectory() + self.originalDir:Path|None = None + + def __enter__(self): + self.originalDir = locator.outputDir + locator.outputDir = Path(self.tempDir.name) + return self + + def __exit__(self, errorType, errorValue, trackback): + locator.outputDir = self.originalDir + self.tempDir.cleanup() + return False + + return Context() + def biomeModifiers(self, modName:str|None=None, dataPackName:str|None=None) -> Path: return self.dataPackMod(modName, dataPackName) / "neoforge" / "biome_modifier" diff --git a/mcpacker/write/packmetawriter.py b/mcpacker/write/packmetawriter.py new file mode 100644 index 0000000..901e5b5 --- /dev/null +++ b/mcpacker/write/packmetawriter.py @@ -0,0 +1,30 @@ +from mcpacker.model.modpack import ModPack +from mcpacker.write.writer import Writer +from pathlib import Path + +import mcpacker.json as json + + +# Class ############################################################################################ + +class PackMetaWriter(Writer): + + def __init__(self, pack:ModPack, outputDir:Path, formatVersion:int): + super().__init__(pack, outputDir) + self.formatVersion = formatVersion + + @property + def packRoot(self) -> Path: + raise NotImplementedError() + + def doWrite(self): + path = self.packRoot / "pack.mcmeta" + self.resetOutputFile(path) + + with path.open("w") as file: + file.write(json.dumps({ + "pack": { + "pack_format": self.formatVersion, + "description": f"auto-generated overrides for {self.pack.name}" + } + }, indent=" ")) diff --git a/mcpacker/write/resourcepack/metawriter.py b/mcpacker/write/resourcepack/metawriter.py new file mode 100644 index 0000000..b6c1a0c --- /dev/null +++ b/mcpacker/write/resourcepack/metawriter.py @@ -0,0 +1,11 @@ +from mcpacker.write.packmetawriter import PackMetaWriter +from pathlib import Path + + +# Class ############################################################################################ + +class ResourcePackMetaWriter(PackMetaWriter): + + @property + def packRoot(self) -> Path: + return self.locator.resourcePack() diff --git a/mcpacker/write/resourcepack/metawriter_test.py b/mcpacker/write/resourcepack/metawriter_test.py new file mode 100644 index 0000000..18953fa --- /dev/null +++ b/mcpacker/write/resourcepack/metawriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.resourcepack.metawriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/resourcepack/writer.py b/mcpacker/write/resourcepack/writer.py new file mode 100644 index 0000000..a3c1715 --- /dev/null +++ b/mcpacker/write/resourcepack/writer.py @@ -0,0 +1,15 @@ +from mcpacker.write.zipwriter import ZipWriter +from pathlib import Path + + +# Class ############################################################################################ + +class ResourcePackWriter(ZipWriter): + + @property + def archiveFile(self) -> Path: + return self.locator.resourcePacks() / f"{self.pack.name}.jar" + + @property + def gatherFromDir(self) -> Path: + return self.locator.resourcePack() diff --git a/mcpacker/write/resourcepack/writer_test.py b/mcpacker/write/resourcepack/writer_test.py new file mode 100644 index 0000000..1053909 --- /dev/null +++ b/mcpacker/write/resourcepack/writer_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.resourcepack.writer + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/zipwriter.py b/mcpacker/write/zipwriter.py new file mode 100644 index 0000000..b9e8ee8 --- /dev/null +++ b/mcpacker/write/zipwriter.py @@ -0,0 +1,39 @@ +from collections.abc import Iterable +from mcpacker.model.modpack import ModPack +from mcpacker.write.compositewriter import CompositeWriter +from mcpacker.write.writer import Writer +from mcpacker.write.locator import Locator +from pathlib import Path +from zipfile import ZipFile +from zipfile import ZIP_DEFLATED + +import mcpacker.json as json +import os + + +# Class ############################################################################################ + +class ZipWriter(CompositeWriter): + + @property + def archiveFile(self) -> Path: + raise NotImplementedError() + + @property + def gatherFromDir(self) -> Path: + raise NotImplementedError() + + def doWrite(self): + archiveFile = self.archiveFile # grab before locator moves + + with self.locator.inTempDir(): + for writer in self._writers: + writer.locator.outputDir = self.locator.outputDir + writer.write() + + archiveFile.parent.mkdir(exist_ok=True, parents=True) + + with ZipFile(archiveFile, "w", ZIP_DEFLATED) as zipFile: + for path in self.gatherFromDir.rglob("*"): + if not path.is_file(): continue + zipFile.write(path, path.relative_to(self.gatherFromDir.parent))