improved and completed color calculator
This commit is contained in:
		
							
								
								
									
										16
									
								
								res/color_overrides.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								res/color_overrides.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
{
 | 
			
		||||
	"minecraft:seagrass": [97, 113, 54],
 | 
			
		||||
	"minecraft:chest": [171, 121, 45],
 | 
			
		||||
	"minecraft:ender_chest": [48, 67, 71],
 | 
			
		||||
	"minecraft:lily_pad": [32, 128, 48],
 | 
			
		||||
	"minecraft:redstone_wire": [189, 32, 8],
 | 
			
		||||
	"minecraft:cocoa": [150, 87, 26],
 | 
			
		||||
	"minecraft:wheat": [220, 187, 101],
 | 
			
		||||
	"minecraft:carrots": [227, 138, 29],
 | 
			
		||||
	"minecraft:potatoes": [200, 162, 75],
 | 
			
		||||
	"minecraft:beetroots": [191, 37,41],
 | 
			
		||||
	"minecraft:nether_wart": [131, 28, 32],
 | 
			
		||||
	"minecraft:sweet_berry_bush": [60, 110, 66],
 | 
			
		||||
	"minecraft:torchflower_crop": [130, 158, 85],
 | 
			
		||||
	"minecraft:pitcher_crop": [112, 134, 181]
 | 
			
		||||
}
 | 
			
		||||
@@ -1,44 +1,242 @@
 | 
			
		||||
import json
 | 
			
		||||
import os
 | 
			
		||||
import platform
 | 
			
		||||
import re
 | 
			
		||||
import tempfile
 | 
			
		||||
import zipfile
 | 
			
		||||
 | 
			
		||||
import pygame
 | 
			
		||||
 | 
			
		||||
from src.utils.paths import get_project_path, CACHE_DIR
 | 
			
		||||
 | 
			
		||||
# Textures with these parts will be excluded
 | 
			
		||||
EXCLUDE = {
 | 
			
		||||
    "bottom", "side", "front", "cracked", "on", "stem", "tip", "lit", "inner"
 | 
			
		||||
    "bottom", "side", "front", "destroy", "on", "tip", "lit", "inner"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Textures with these names will be copied to their variants (variants listed in `VARIANTS`)
 | 
			
		||||
# Tuples indicate a change of name for variants
 | 
			
		||||
TO_VARIANT = [
 | 
			
		||||
    ("nether_bricks", "nether_brick"),
 | 
			
		||||
    ("nether_bricks", "nether_brick"),
 | 
			
		||||
    ("oak_planks", "oak"),
 | 
			
		||||
    ("spruce_planks", "spruce"),
 | 
			
		||||
    ("birch_planks", "birch"),
 | 
			
		||||
    ("jungle_planks", "jungle"),
 | 
			
		||||
    ("acacia_planks", "acacia"),
 | 
			
		||||
    ("dark_oak_planks", "dark_oak"),
 | 
			
		||||
    ("mangrove_planks", "mangrove"),
 | 
			
		||||
    ("cherry_planks", "cherry"),
 | 
			
		||||
    ("bamboo_mosaic", "bamboo"),
 | 
			
		||||
    ("crimson_planks", "crimson"),
 | 
			
		||||
    ("warped_planks", "warped"),
 | 
			
		||||
    "stone",
 | 
			
		||||
    "cobblestone",
 | 
			
		||||
    "mossy_cobblestone",
 | 
			
		||||
    "smooth_stone",
 | 
			
		||||
    ("stone_bricks", "stone_brick"),
 | 
			
		||||
    ("mossy_stone_bricks", "mossy_stone_brick"),
 | 
			
		||||
    "granite",
 | 
			
		||||
    "polished_granite",
 | 
			
		||||
    "diorite",
 | 
			
		||||
    "polished_diorite",
 | 
			
		||||
    "andesite",
 | 
			
		||||
    "polished_andesite",
 | 
			
		||||
    "cobbled_deepslate",
 | 
			
		||||
    "polished_deepslate",
 | 
			
		||||
    ("deepslate_bricks", "deepslate_brick"),
 | 
			
		||||
    ("deepslate_tiles", "deepslate_tile"),
 | 
			
		||||
    ("bricks", "brick"),
 | 
			
		||||
    ("mud_bricks", "mud_brick"),
 | 
			
		||||
    "sandstone",
 | 
			
		||||
    "smooth_sandstone",
 | 
			
		||||
    "cut_sandstone",
 | 
			
		||||
    "red_sandstone",
 | 
			
		||||
    "smooth_red_sandstone",
 | 
			
		||||
    "cut_red_sandstone",
 | 
			
		||||
    "prismarine",
 | 
			
		||||
    ("prismarine_bricks", "prismarine_brick"),
 | 
			
		||||
    "dark_prismarine",
 | 
			
		||||
    ("red_nether_bricks", "red_nether_brick"),
 | 
			
		||||
    "blackstone",
 | 
			
		||||
    "polished_blackstone",
 | 
			
		||||
    ("polished_blackstone_bricks", "polished_blackstone_brick"),
 | 
			
		||||
    ("end_stone_bricks", "end_stone_brick"),
 | 
			
		||||
    ("purpur_block", "purpur"),
 | 
			
		||||
    ("quartz_block", "quartz"),
 | 
			
		||||
    "smooth_quartz",
 | 
			
		||||
    "cut_copper",
 | 
			
		||||
    "exposed_cut_copper",
 | 
			
		||||
    "weathered_cut_copper",
 | 
			
		||||
    "oxidized_cut_copper",
 | 
			
		||||
    "waxed_cut_copper",
 | 
			
		||||
    "waxed_exposed_cut_copper",
 | 
			
		||||
    "waxed_weathered_cut_copper",
 | 
			
		||||
    "waxed_oxidized_cut_copper",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Variants of the textures in `TO_VARIANT`
 | 
			
		||||
VARIANTS = [
 | 
			
		||||
    "slab", "stairs",
 | 
			
		||||
    "wall", "fence", "fence_gate",
 | 
			
		||||
    "pressure_plate", "button",
 | 
			
		||||
    "sign", "wall_sign", "hanging_sign", "wall_hanging_sign"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Colors to copy
 | 
			
		||||
TO_COPY = [
 | 
			
		||||
    ("minecraft:furnace", "minecraft:dropper"),
 | 
			
		||||
    ("minecraft:furnace", "minecraft:dispenser"),
 | 
			
		||||
    ("minecraft:furnace", "minecraft:piston"),
 | 
			
		||||
    ("minecraft:furnace", "minecraft:sticky_piston"),
 | 
			
		||||
    ("minecraft:oak_planks", "minecraft:piston_head"),
 | 
			
		||||
    ("minecraft:oak_planks", "minecraft:sticky_piston_head"),
 | 
			
		||||
    ("minecraft:torch", "minecraft:wall_torch"),
 | 
			
		||||
    ("minecraft:soul_torch", "minecraft:soul_wall_torch"),
 | 
			
		||||
    ("minecraft:redstone_torch", "minecraft:redstone_wall_torch"),
 | 
			
		||||
    ("minecraft:snow", "minecraft:snow_block"),
 | 
			
		||||
    ("minecraft:water", "minecraft:bubble_column"),
 | 
			
		||||
    ("minecraft:sandstone", "minecraft:smooth_sandstone"),
 | 
			
		||||
    ("minecraft:red_sandstone", "minecraft:smooth_red_sandstone"),
 | 
			
		||||
    ("minecraft:quartz_block", "minecraft:smooth_quartz"),
 | 
			
		||||
    ("minecraft:dripstone_block", "minecraft:pointed_dripstone"),
 | 
			
		||||
    ("minecraft:oak_log", "minecraft:oak_wood"),
 | 
			
		||||
    ("minecraft:spruce_log", "minecraft:spruce_wood"),
 | 
			
		||||
    ("minecraft:birch_log", "minecraft:birch_wood"),
 | 
			
		||||
    ("minecraft:acacia_log", "minecraft:acacia_wood"),
 | 
			
		||||
    ("minecraft:jungle_log", "minecraft:jungle_wood"),
 | 
			
		||||
    ("minecraft:cherry_log", "minecraft:cherry_wood"),
 | 
			
		||||
    ("minecraft:mangrove_log", "minecraft:mangrove_wood"),
 | 
			
		||||
    ("minecraft:dark_oak_log", "minecraft:dark_oak_wood"),
 | 
			
		||||
    ("minecraft:stripped_oak_log", "minecraft:stripped_oak_wood"),
 | 
			
		||||
    ("minecraft:stripped_spruce_log", "minecraft:stripped_spruce_wood"),
 | 
			
		||||
    ("minecraft:stripped_birch_log", "minecraft:stripped_birch_wood"),
 | 
			
		||||
    ("minecraft:stripped_acacia_log", "minecraft:stripped_acacia_wood"),
 | 
			
		||||
    ("minecraft:stripped_jungle_log", "minecraft:stripped_jungle_wood"),
 | 
			
		||||
    ("minecraft:stripped_cherry_log", "minecraft:stripped_cherry_wood"),
 | 
			
		||||
    ("minecraft:stripped_mangrove_log", "minecraft:stripped_mangrove_wood"),
 | 
			
		||||
    ("minecraft:stripped_dark_oak_log", "minecraft:stripped_dark_oak_wood"),
 | 
			
		||||
    ("minecraft:magma", "minecraft:magma_block"),
 | 
			
		||||
    ("minecraft:cut_copper", "minecraft:waxed_cut_copper"),
 | 
			
		||||
    ("minecraft:exposed_cut_copper", "minecraft:waxed_exposed_cut_copper"),
 | 
			
		||||
    ("minecraft:weathered_cut_copper", "minecraft:waxed_weathered_cut_copper"),
 | 
			
		||||
    ("minecraft:oxidized_cut_copper", "minecraft:waxed_oxidized_cut_copper"),
 | 
			
		||||
    ("minecraft:iron_block", "minecraft:heavy_weighted_pressure_plate"),
 | 
			
		||||
    ("minecraft:gold_block", "minecraft:light_weighted_pressure_plate"),
 | 
			
		||||
    ("minecraft:bricks", "minecraft:flower_pot"),
 | 
			
		||||
    ("minecraft:oak_log", "minecraft:campfire"),
 | 
			
		||||
    ("minecraft:oak_log", "minecraft:soul_campfire"),
 | 
			
		||||
    ("minecraft:moss_block", "minecraft:moss_carpet"),
 | 
			
		||||
    ("minecraft:stone", "minecraft:infested_stone"),
 | 
			
		||||
    ("minecraft:cobblestone", "minecraft:infested_cobblestone"),
 | 
			
		||||
    ("minecraft:stone_bricks", "minecraft:infested_stone_bricks"),
 | 
			
		||||
    ("minecraft:mossy_stone_bricks", "minecraft:infested_mossy_stone_bricks"),
 | 
			
		||||
    ("minecraft:chiseled_stone_bricks", "minecraft:infested_chiseled_stone_bricks"),
 | 
			
		||||
    ("minecraft:deepslate", "minecraft:infested_deepslate"),
 | 
			
		||||
    ("minecraft:infested_stone_bricks", "minecraft:cracked_infested_stone_bricks"),
 | 
			
		||||
    ("minecraft:cauldron", "minecraft:water_cauldron"),
 | 
			
		||||
    ("minecraft:cauldron", "minecraft:lava_cauldron"),
 | 
			
		||||
    ("minecraft:cauldron", "minecraft:powder_snow_cauldron"),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Wool colors
 | 
			
		||||
WOOLS = [
 | 
			
		||||
    "red", "blue", "cyan", "gray",
 | 
			
		||||
    "lime", "pink", "black", "brown",
 | 
			
		||||
    "green", "white", "orange", "purple",
 | 
			
		||||
    "yellow", "magenta", "light_blue", "light_gray"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Wool variants
 | 
			
		||||
WOOL_VARIANTS = [
 | 
			
		||||
    "carpet", "bed", "banner", "wall_banner"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# These will be removed from the textures' names
 | 
			
		||||
TO_STRIP = ["_top", "_stalk", "_end", "_round", "_still"]
 | 
			
		||||
 | 
			
		||||
# Minecraft version
 | 
			
		||||
MC_VERSION = "1.20.1"
 | 
			
		||||
 | 
			
		||||
# Minecraft root directory (platform dependent)
 | 
			
		||||
MC_ROOT = os.path.expanduser({
 | 
			
		||||
    "Linux": r"~/.minecraft",
 | 
			
		||||
    "Darwin": r"~/Library/Application Support/minecraft",
 | 
			
		||||
    "Windows": r"%APPDATA%\.minecraft"
 | 
			
		||||
}[platform.system()])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def extract_textures(jar_path: str, outdir: str) -> None:
 | 
			
		||||
    with zipfile.ZipFile(jar_path) as f:
 | 
			
		||||
        for info in f.infolist():
 | 
			
		||||
            path = info.filename
 | 
			
		||||
            if not re.match(r"^assets/minecraft/textures/block/[^/]+\.png$", path):
 | 
			
		||||
                continue
 | 
			
		||||
            info.filename = os.path.basename(path)
 | 
			
		||||
            f.extract(info, outdir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main() -> None:
 | 
			
		||||
    print(f"[1/5] Extracting Minecraft {MC_VERSION} textures")
 | 
			
		||||
    jar_path = os.path.join(MC_ROOT, "versions", MC_VERSION, f"{MC_VERSION}.jar")
 | 
			
		||||
 | 
			
		||||
    if not os.path.exists(jar_path):
 | 
			
		||||
        print(f"Couldn't find Minecraft {MC_VERSION} JAR file")
 | 
			
		||||
        print(f"Not at {jar_path}")
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    workdir = tempfile.TemporaryDirectory()
 | 
			
		||||
    extract_textures(jar_path, workdir.name)
 | 
			
		||||
 | 
			
		||||
    pygame.init()
 | 
			
		||||
    win = pygame.display.set_mode((1, 1))
 | 
			
		||||
    path = "/tmp/minecraft/textures/block"
 | 
			
		||||
    with open("/tmp/overrides.json", "r") as f:
 | 
			
		||||
        overrides = json.load(f)
 | 
			
		||||
    pygame.display.set_mode((1, 1), pygame.NOFRAME | pygame.HIDDEN)
 | 
			
		||||
 | 
			
		||||
    colors = {}
 | 
			
		||||
    paths = os.listdir(path)
 | 
			
		||||
    paths = os.listdir(workdir.name)
 | 
			
		||||
    total = len(paths)
 | 
			
		||||
    skipped = 0
 | 
			
		||||
    print("[2/5] Averaging textures")
 | 
			
		||||
    for i, filename in enumerate(paths):
 | 
			
		||||
        print(f"\r{i+1}/{total} ({i/total*100:.2f}%) {filename}", end="")
 | 
			
		||||
        block, ext = filename.rsplit(".", 1)
 | 
			
		||||
        if ext != "png":
 | 
			
		||||
            skipped += 1
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        parts = set(block.split("_"))
 | 
			
		||||
        if not parts.isdisjoint(EXCLUDE):
 | 
			
		||||
            skipped += 1
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        block = block.replace("_top", "")
 | 
			
		||||
        img = pygame.image.load(os.path.join(path, filename)).convert_alpha()
 | 
			
		||||
        for s in TO_STRIP:
 | 
			
		||||
            block = block.replace(s, "")
 | 
			
		||||
        img = pygame.image.load(os.path.join(workdir.name, filename)).convert_alpha()
 | 
			
		||||
        color = pygame.transform.average_color(img, consider_alpha=True)
 | 
			
		||||
        colors[f"minecraft:{block}"] = color[:3]
 | 
			
		||||
        color = color[:3]
 | 
			
		||||
        colors[f"minecraft:{block}"] = color
 | 
			
		||||
 | 
			
		||||
    print(f"\r{total}/{total} (100%) Finished")
 | 
			
		||||
    print(f"Skipped {skipped} files")
 | 
			
		||||
 | 
			
		||||
    print("[3/5] Applying overrides")
 | 
			
		||||
    with open(get_project_path("res", "color_overrides.json"), "r") as f:
 | 
			
		||||
        overrides = json.load(f)
 | 
			
		||||
    colors.update(overrides)
 | 
			
		||||
    with open("/tmp/colors.json", "w") as f:
 | 
			
		||||
 | 
			
		||||
    print("[4/5] Generating variants")
 | 
			
		||||
    for to_variant in TO_VARIANT:
 | 
			
		||||
        src = to_variant[0] if isinstance(to_variant, tuple) else to_variant
 | 
			
		||||
        dst = to_variant[1] if isinstance(to_variant, tuple) else to_variant
 | 
			
		||||
 | 
			
		||||
        for variant in VARIANTS:
 | 
			
		||||
            TO_COPY.append((f"minecraft:{src}", f"minecraft:{dst}_{variant}"))
 | 
			
		||||
 | 
			
		||||
    for color in WOOLS:
 | 
			
		||||
        for variant in WOOL_VARIANTS:
 | 
			
		||||
            TO_COPY.append((f"minecraft:{color}_wool", f"minecraft:{color}_{variant}"))
 | 
			
		||||
 | 
			
		||||
    for src, dst in TO_COPY:
 | 
			
		||||
        colors[dst] = colors[src]
 | 
			
		||||
 | 
			
		||||
    print("[5/5] Exporting colors")
 | 
			
		||||
    outpath = os.path.join(CACHE_DIR, "colors.json")
 | 
			
		||||
    with open(outpath, "w") as f:
 | 
			
		||||
        json.dump(colors, f, indent=4)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/utils/paths.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/utils/paths.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
import os.path
 | 
			
		||||
 | 
			
		||||
import platformdirs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
APP_NAME = "lycacraft-paths"
 | 
			
		||||
APP_AUTHOR = "lycacraft"
 | 
			
		||||
CACHE_DIR = platformdirs.user_cache_dir(appname=APP_NAME, appauthor=APP_AUTHOR, ensure_exists=True)
 | 
			
		||||
CONFIG_DIR = platformdirs.user_config_dir(appname=APP_NAME, appauthor=APP_AUTHOR, ensure_exists=True)
 | 
			
		||||
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_project_path(*elmts: str) -> str:
 | 
			
		||||
    return os.path.join(ROOT, *elmts)
 | 
			
		||||
		Reference in New Issue
	
	Block a user