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

182 lines
5.9 KiB
Python
Raw Normal View History

2024-05-22 11:04:13 +03:00
#!/usr/bin/env python3
import json
from pathlib import Path
from typing import Union
2024-05-22 11:04:13 +03:00
import asyncio
from httpx import AsyncClient
from rich.progress import Progress
2024-05-22 11:04:13 +03:00
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"):
2024-05-22 11:04:13 +03:00
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)
2024-05-22 11:04:13 +03:00
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")
2024-05-22 11:04:13 +03:00
print("[ + ] Creating connected textures")
2024-05-22 13:17:31 +03:00
(OUTPUT_PATH / "assets/seasonsextras/textures/block").mkdir(
exist_ok=True, parents=True
)
2024-05-22 11:04:13 +03:00
for color in GLASS_COLORS:
out_path = GLASS_OUTPUT_PATH / color
out_path.mkdir(exist_ok=True)
2024-05-22 13:04:44 +03:00
texture_name = f"{color}_greenhouse_glass"
with (out_path / f"{texture_name}.properties").open("w") as fp:
2024-05-22 11:04:13 +03:00
fp.write("method=ctm\n")
2024-05-22 13:04:44 +03:00
fp.write(f"matchBlocks=seasonsextras:{texture_name}\n")
2024-05-22 11:04:13 +03:00
fp.write(f"tiles=0-46\n")
fp.write(f"connect=block\n")
fp.write(
2024-05-22 13:49:55 +03:00
f"resourceCondition=seasonextras:textures/block/{texture_name}.png\n"
)
2024-05-22 11:04:13 +03:00
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
2024-05-22 13:14:48 +03:00
/ f"assets/seasonsextras/textures/block/{texture_name}.png"
)
2024-05-22 11:04:13 +03:00
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:
2024-05-22 11:09:40 +03:00
zipf.write(GLASS_OUTPUT_PATH / "purple" / "0.png", "pack.png")
for file in OUTPUT_PATH.rglob("*"):
zipf.write(file, Path(*file.parts[1:]))
2024-05-22 11:04:13 +03:00
2024-05-22 11:04:13 +03:00
if __name__ == "__main__":
from sys import argv
asyncio.run(main(*argv[1:]))