continuity-fabric-seasons-c.../make.py

182 lines
5.9 KiB
Python

#!/usr/bin/env python3
import json
from pathlib import Path
from typing import Union
import asyncio
from httpx import AsyncClient
from rich.progress import Progress
from zipfile import ZipFile
from PIL import Image
INPUT_PATH = Path("input/")
TEXTURES_CACHE = INPUT_PATH / "textures_cache"
GLASS_CACHE_SEAMLESS = INPUT_PATH / "glass_seamless"
OUTPUT_PATH = Path("output/")
GLASS_OUTPUT_PATH = (
OUTPUT_PATH / "assets/minecraft/optifine/ctm/greenhouse/glass"
)
TEXTURES_PATH: str = "assets/minecraft/textures"
GLASS_COLORS: list[str] = [
"black",
"blue",
"brown",
"cyan",
"gray",
"green",
"light_blue",
"light_gray",
"lime",
"magenta",
"orange",
"pink",
"purple",
"red",
"white",
"yellow",
]
meta_url: str = (
"https://piston-meta.mojang.com/v1/packages/715ccf3330885e75b205124f09f8712542cbe7e0/1.20.1.json"
)
meta_filename = INPUT_PATH / f"meta-{meta_url.split('/')[-1]}"
async def download_if_missing(url: str, path: Union[Path, str]):
path = Path(path)
if path.exists():
return
with Progress() as progress:
task = progress.add_task(f"Downloading {path}")
with Path(path).open("wb") as fout:
async with AsyncClient() as client:
async with client.stream("GET", url) as req:
progress.update(
task,
total=int(req.headers.get("Content-Length", 0)),
completed=0,
)
async for chunk in req.aiter_bytes(8192):
progress.advance(task, fout.write(chunk))
async def main(seam_texture: str = "block.dark_oak_planks"):
INPUT_PATH.mkdir(exist_ok=True)
TEXTURES_CACHE.mkdir(exist_ok=True)
GLASS_CACHE_SEAMLESS.mkdir(exist_ok=True)
OUTPUT_PATH.mkdir(exist_ok=True)
GLASS_OUTPUT_PATH.mkdir(exist_ok=True, parents=True)
print("[ + ] Getting client info")
await download_if_missing(meta_url, meta_filename)
with open(meta_filename, "r") as fp:
meta: dict = json.load(fp)
print("[ + ] Getting client JAR")
client_filename = INPUT_PATH / f"client-{meta['id']}.jar"
await download_if_missing(
meta["downloads"]["client"]["url"], client_filename
)
# "assets/minecraft/textures/block/orange_stained_glass.png"
with ZipFile(client_filename) as zipf:
def extract_texture(name: str) -> Path:
path = f"{TEXTURES_PATH}/{name.replace('.', '/')}.png"
out_path = TEXTURES_CACHE / f"{name}.png"
if out_path.exists():
print("[---] Extracted", name, "already")
return out_path
print("[...] Extracting", name)
with zipf.open(path, "r") as fp_in:
with out_path.open("wb") as fp_out:
while chunk := fp_in.read():
fp_out.write(chunk)
return out_path
extract_texture(seam_texture)
for color in GLASS_COLORS:
extract_texture(f"block.{color}_stained_glass")
print("[ + ] Removing seam on glass textures")
for color in GLASS_COLORS:
in_path = TEXTURES_CACHE / f"block.{color}_stained_glass.png"
out_file = GLASS_CACHE_SEAMLESS / f"{color}.png"
if out_file.exists():
print("[---] SKIP", out_file.name)
continue
print("[...]", out_file.name)
with Image.open(in_path).convert("RGBA") as im:
im.paste(im.crop((1, 1, 2, 15)), (0, 0))
im.paste(im.crop((1, 1, 2, 15)), (0, 2))
im.paste(im.crop((1, 1, 2, 15)), (15, 0))
im.paste(im.crop((1, 1, 2, 15)), (15, 2))
im.paste(im.crop((1, 1, 15, 2)), (1, 0))
im.paste(im.crop((1, 1, 15, 2)), (1, 15))
im.save(out_file)
print("[ + ] Loading connected textures masks")
ctm_list: list[Image.Image] = []
with Image.open("ctm.png") as im:
for i in range(47):
ox, oy = (i % 8) * 16, (i // 8) * 16
ctm_list.append(im.crop((ox, oy, ox + 16, oy + 16)).convert("1"))
border_texture = Image.open(TEXTURES_CACHE / f"{seam_texture}.png")
print("[ + ] Creating connected textures")
(OUTPUT_PATH / "assets/seasonsextras/textures/block").mkdir(
exist_ok=True, parents=True
)
for color in GLASS_COLORS:
out_path = GLASS_OUTPUT_PATH / color
out_path.mkdir(exist_ok=True)
texture_name = f"{color}_greenhouse_glass"
with (out_path / f"{texture_name}.properties").open("w") as fp:
fp.write("method=ctm\n")
fp.write(f"matchBlocks=seasonsextras:{texture_name}\n")
fp.write(f"tiles=0-46\n")
fp.write(f"connect=block\n")
fp.write(
f"resourceCondition=seasonextras:textures/block/{texture_name}.png\n"
)
with Image.open(GLASS_CACHE_SEAMLESS / f"{color}.png") as glass:
for i in range(47):
ctm = Image.composite(border_texture, glass, ctm_list[i])
ctm.save(out_path / f"{i}.png")
if i == 0:
ctm.save(
OUTPUT_PATH
/ f"assets/seasonsextras/textures/block/{texture_name}.png"
)
with (OUTPUT_PATH / "pack.mcmeta").open("w") as fp:
json.dump(
{
"pack": {
"pack_format": 15,
"description": f"CTM support for Fabric Seasons Extras. {seam_texture}",
}
},
fp,
indent=2,
ensure_ascii=False,
)
with ZipFile(
f"seasons-ctm-{seam_texture.split('.', 1)[-1]}.zip", "w"
) as zipf:
zipf.write(GLASS_OUTPUT_PATH / "purple" / "0.png", "pack.png")
for file in OUTPUT_PATH.rglob("*"):
zipf.write(file, Path(*file.parts[1:]))
if __name__ == "__main__":
from sys import argv
asyncio.run(main(*argv[1:]))