#!/usr/bin/env python3 """Generate 16x16 block textures for smart_crafting_table, post_office, mailbox.""" from pathlib import Path from PIL import Image ROOT = Path(__file__).resolve().parent.parent # ── Palette ───────────────────────────────────────────────── OAK_LIGHT = (150, 110, 65) OAK_DARK = (115, 80, 45) OAK_SHADOW = (80, 55, 28) GOLD = (218, 165, 32) GOLD_BRIGHT = (255, 214, 85) REDSTONE = (210, 40, 40) REDSTONE_BRIGHT = (255, 90, 90) BRICK_RED = (138, 58, 48) BRICK_DARK = (92, 38, 30) MORTAR = (68, 52, 42) SLATE = (58, 62, 70) CREAM = (240, 225, 190) ENVELOPE_LINE = (45, 30, 20) STAMP_RED = (190, 50, 50) MB_RED = (175, 40, 40) MB_RED_DARK = (115, 25, 25) MB_RED_HL = (220, 75, 75) MB_BLACK = (20, 20, 20) MB_FLAG = (235, 190, 55) MB_POST = (90, 60, 35) # Tent canvas — weathered green army-tent fabric CANVAS_LIGHT = (118, 138, 88) CANVAS_MID = (90, 110, 68) CANVAS_DARK = (66, 84, 50) CANVAS_SHADOW = (44, 58, 36) CANVAS_STITCH = (190, 175, 130) def save(img: Image.Image, rel: str) -> None: out = ROOT / rel out.parent.mkdir(parents=True, exist_ok=True) img.save(out) print(f"wrote {rel}") def px(img: Image.Image, x: int, y: int, color) -> None: if 0 <= x < img.width and 0 <= y < img.height: img.putpixel((x, y), color) def rect(img: Image.Image, x0: int, y0: int, x1: int, y1: int, color) -> None: for y in range(y0, y1 + 1): for x in range(x0, x1 + 1): px(img, x, y, color) # ── Smart Crafting Table ─────────────────────────────────── # Top-down style: oak planks, bold gold frame, 2x2 inlay with redstone + diamond. def smart_crafting_table() -> Image.Image: img = Image.new("RGBA", (16, 16), OAK_LIGHT) # Oak plank background with subtle grain for y in range(16): band = (y // 4) % 2 color = OAK_LIGHT if band == 0 else OAK_DARK rect(img, 0, y, 15, y, color) # Knots / grain speckle for (x, y) in [(3, 1), (11, 2), (6, 5), (13, 6), (2, 9), (9, 10), (5, 13), (12, 14)]: px(img, x, y, OAK_SHADOW) # Plank seams for y in (3, 7, 11): rect(img, 0, y, 15, y, OAK_SHADOW) # Bold gold frame (2px thick) rect(img, 0, 0, 15, 1, GOLD) rect(img, 0, 14, 15, 15, GOLD) rect(img, 0, 0, 1, 15, GOLD) rect(img, 14, 0, 15, 15, GOLD) # Inner frame highlight rect(img, 1, 1, 14, 1, GOLD_BRIGHT) rect(img, 1, 14, 14, 14, (165, 120, 20)) rect(img, 1, 2, 1, 13, GOLD_BRIGHT) rect(img, 14, 2, 14, 13, (165, 120, 20)) # Corner rivets for (x, y) in [(0, 0), (15, 0), (0, 15), (15, 15)]: px(img, x, y, (90, 65, 10)) # 2x2 inset panels with gold dividers at mid (x=7..8, y=7..8) # Top-left = redstone, top-right = diamond, bottom-left = emerald, bottom-right = gold ingot TL = (3, 3, 6, 6) # redstone area TR = (9, 3, 12, 6) # diamond area BL = (3, 9, 6, 12) # emerald area BR = (9, 9, 12, 12) # gold area # Dark recessed wells for (x0, y0, x1, y1) in (TL, TR, BL, BR): rect(img, x0, y0, x1, y1, (40, 25, 12)) # Redstone gem (red) rect(img, 4, 4, 5, 5, REDSTONE) px(img, 4, 4, REDSTONE_BRIGHT) # Diamond (cyan) rect(img, 10, 4, 11, 5, (120, 220, 235)) px(img, 10, 4, (200, 250, 255)) # Emerald (green) rect(img, 4, 10, 5, 11, (50, 170, 90)) px(img, 4, 10, (120, 220, 150)) # Gold nugget rect(img, 10, 10, 11, 11, GOLD) px(img, 10, 10, GOLD_BRIGHT) # Gold cross dividers rect(img, 7, 2, 8, 13, GOLD) rect(img, 2, 7, 13, 8, GOLD) # Center jewel px(img, 7, 7, REDSTONE_BRIGHT) px(img, 8, 7, REDSTONE_BRIGHT) px(img, 7, 8, REDSTONE) px(img, 8, 8, REDSTONE) return img # ── Post Office ──────────────────────────────────────────── # Big envelope front: cream background, bold dark fold lines, red stamp, "POST" bar. def post_office() -> Image.Image: img = Image.new("RGBA", (16, 16), CREAM) # Outer envelope border (1px) rect(img, 0, 0, 15, 0, ENVELOPE_LINE) rect(img, 0, 15, 15, 15, ENVELOPE_LINE) rect(img, 0, 0, 0, 15, ENVELOPE_LINE) rect(img, 15, 0, 15, 15, ENVELOPE_LINE) # Paper shade (slight gradient on bottom half) for y in range(8, 15): for x in range(1, 15): if (x + y) % 3 == 0: px(img, x, y, (225, 210, 175)) # Envelope fold: top-left and top-right diagonals meeting at center-top # Lines go from (1,1) -> (7,7) and (14,1) -> (8,7) for i in range(7): px(img, 1 + i, 1 + i, ENVELOPE_LINE) px(img, 14 - i, 1 + i, ENVELOPE_LINE) # Second pass for thickness for i in range(6): px(img, 2 + i, 1 + i, (90, 70, 50)) px(img, 13 - i, 1 + i, (90, 70, 50)) # Horizontal seam at y=8 (where flaps meet paper) rect(img, 1, 8, 14, 8, ENVELOPE_LINE) # Red stamp: top-right square (3x3) with crosshatch rect(img, 11, 2, 13, 4, STAMP_RED) px(img, 12, 3, (255, 220, 220)) # stamp center highlight # Stamp border px(img, 10, 2, ENVELOPE_LINE) px(img, 10, 3, ENVELOPE_LINE) px(img, 10, 4, ENVELOPE_LINE) px(img, 11, 5, ENVELOPE_LINE) px(img, 12, 5, ENVELOPE_LINE) px(img, 13, 5, ENVELOPE_LINE) # Address bar: dark rectangle bottom-center reading like lines of text rect(img, 3, 11, 12, 12, (120, 100, 75)) rect(img, 3, 13, 10, 13, (120, 100, 75)) # "POST" mark: a small red circle stamp bottom-right rect(img, 11, 11, 13, 13, STAMP_RED) px(img, 11, 11, (0, 0, 0, 0)) px(img, 13, 11, (0, 0, 0, 0)) px(img, 11, 13, (0, 0, 0, 0)) px(img, 13, 13, (0, 0, 0, 0)) px(img, 12, 12, (255, 230, 230)) return img # ── Mailbox ─────────────────────────────────────────────── # Classic red pillar-mailbox front: domed top, slot, base, flag. def mailbox() -> Image.Image: img = Image.new("RGBA", (16, 16), (0, 0, 0, 0)) # Post base (wooden) across bottom rect(img, 6, 14, 9, 15, MB_POST) px(img, 6, 14, (70, 45, 25)) px(img, 9, 14, (70, 45, 25)) # Mailbox body (rounded: rows 2..13) # Body rectangle x=2..13, y=4..13 rect(img, 2, 4, 13, 13, MB_RED) # Rounded top corners px(img, 2, 4, (0, 0, 0, 0)) px(img, 13, 4, (0, 0, 0, 0)) # Add a dome/top-bump rect(img, 3, 2, 12, 3, MB_RED) px(img, 3, 2, (0, 0, 0, 0)) px(img, 12, 2, (0, 0, 0, 0)) rect(img, 4, 1, 11, 1, MB_RED) rect(img, 5, 0, 10, 0, MB_RED_DARK) # Left-side highlight (lighter vertical stripe) rect(img, 3, 5, 3, 12, MB_RED_HL) px(img, 4, 2, MB_RED_HL) # Right-side shadow rect(img, 12, 5, 12, 12, MB_RED_DARK) rect(img, 11, 13, 13, 13, MB_RED_DARK) # Black letter slot (horizontal bar) rect(img, 5, 6, 10, 7, MB_BLACK) # Slot highlight rect(img, 5, 6, 10, 6, (50, 50, 50)) # Circular latch below slot px(img, 7, 10, MB_BLACK) px(img, 8, 10, MB_BLACK) px(img, 7, 11, MB_BLACK) px(img, 8, 11, MB_BLACK) px(img, 7, 10, (90, 90, 90)) # Yellow flag on the right side rect(img, 14, 3, 15, 6, MB_FLAG) px(img, 14, 3, (180, 140, 40)) px(img, 15, 6, (180, 140, 40)) # Flag pole rect(img, 14, 7, 14, 10, (60, 60, 60)) return img # ── Tent Canvas ──────────────────────────────────────────── # Weathered army-canvas fabric: subtle horizontal weave + occasional darker # mottling + a vertical seam stitch line. Fully opaque so it doesn't ghost # against the alpha_test renderer. def tent_canvas() -> Image.Image: img = Image.new("RGBA", (16, 16), CANVAS_MID) # Horizontal weave bands (every 2 rows alternating tone) for y in range(16): row = CANVAS_MID if (y // 2) % 2 == 0 else CANVAS_DARK rect(img, 0, y, 15, y, row) # Diagonal weave specks for fabric texture for y in range(16): for x in range(16): if (x + y) % 5 == 0: px(img, x, y, CANVAS_LIGHT) elif (x - y) % 7 == 0: px(img, x, y, CANVAS_SHADOW) # Wear / sun-bleached patches (clusters) for (x, y) in [(2, 3), (3, 3), (10, 6), (11, 6), (5, 11), (6, 11), (13, 12)]: px(img, x, y, CANVAS_LIGHT) # Vertical seam stitch down the center for y in range(0, 16, 2): px(img, 7, y, CANVAS_STITCH) px(img, 8, y, CANVAS_SHADOW) # Edge darken (gives the panel some depth at block boundaries) rect(img, 0, 0, 15, 0, CANVAS_SHADOW) rect(img, 0, 15, 15, 15, CANVAS_SHADOW) rect(img, 0, 0, 0, 15, CANVAS_SHADOW) rect(img, 15, 0, 15, 15, CANVAS_SHADOW) return img # ── Mailbox v2 — block-style (full 16x16 face, no transparency) ─ # The previous sprite was an item-sized icon centered on transparency, which # reads as a placeholder when applied to all 6 faces of a cube. This version # fills the face: red body panel, vertical seam, slot, latch, riveted corners. def mailbox_block() -> Image.Image: img = Image.new("RGBA", (16, 16), MB_RED) # Vertical highlight strip on the left rect(img, 0, 0, 1, 15, MB_RED_HL) # Vertical shadow strip on the right rect(img, 14, 0, 15, 15, MB_RED_DARK) # Top dome highlight (1px band) rect(img, 2, 0, 13, 0, MB_RED_HL) # Bottom shadow band rect(img, 2, 15, 13, 15, MB_RED_DARK) # Horizontal mail slot (centered) rect(img, 4, 6, 11, 8, MB_BLACK) rect(img, 4, 6, 11, 6, (50, 50, 50)) # slot lip highlight rect(img, 4, 8, 11, 8, (5, 5, 5)) # slot lip shadow # Round latch below the slot rect(img, 7, 11, 8, 12, MB_BLACK) px(img, 7, 11, (90, 90, 90)) # Yellow flag emblem in the top-right corner rect(img, 12, 2, 13, 4, MB_FLAG) px(img, 12, 2, (180, 140, 40)) # Flag pole px(img, 13, 5, (60, 60, 60)) # Rivets in the corners for (x, y) in [(2, 2), (13, 2), (2, 13), (13, 13)]: px(img, x, y, (40, 15, 15)) return img # ── Post Office v2 — block-style facade ───────────────────── # A small post-office building face: brick wall, "POST" plaque, awning hint. def post_office_block() -> Image.Image: img = Image.new("RGBA", (16, 16), BRICK_RED) # Brick courses with mortar lines (offset every other row) for y in range(16): # mortar line every 4 rows if y % 4 == 0: rect(img, 0, y, 15, y, MORTAR) else: # vertical mortar joints, offset by course offset = 0 if (y // 4) % 2 == 0 else 4 for x in range(16): if (x + offset) % 8 == 0: px(img, x, y, MORTAR) else: # subtle brick tone variation if (x + y) % 3 == 0: px(img, x, y, BRICK_DARK) # Cream-colored "POST" plaque (centered) rect(img, 2, 5, 13, 10, CREAM) rect(img, 2, 5, 13, 5, ENVELOPE_LINE) # top border rect(img, 2, 10, 13, 10, ENVELOPE_LINE) # bottom border rect(img, 2, 5, 2, 10, ENVELOPE_LINE) # left border rect(img, 13, 5, 13, 10, ENVELOPE_LINE) # right border # "POST" lettering — 4 chunky chars on the plaque # P rect(img, 3, 7, 4, 8, ENVELOPE_LINE); px(img, 3, 6, ENVELOPE_LINE) # O rect(img, 6, 6, 7, 9, ENVELOPE_LINE); px(img, 6, 7, CREAM); px(img, 7, 7, CREAM); px(img, 6, 8, CREAM); px(img, 7, 8, CREAM) # S (simplified stub) rect(img, 9, 6, 10, 6, ENVELOPE_LINE); px(img, 9, 7, ENVELOPE_LINE); rect(img, 9, 8, 10, 8, ENVELOPE_LINE); px(img, 10, 9, ENVELOPE_LINE); rect(img, 9, 9, 10, 9, ENVELOPE_LINE) # T rect(img, 11, 6, 12, 6, ENVELOPE_LINE); rect(img, 11, 7, 11, 9, ENVELOPE_LINE) # Red stamp accent in the top-right rect(img, 12, 1, 14, 3, STAMP_RED) px(img, 13, 2, (255, 220, 220)) # Awning suggestion (alternating red/cream stripes at the top) for x in range(16): if (x // 2) % 2 == 0: px(img, x, 1, (210, 70, 70)) else: px(img, x, 1, CREAM) rect(img, 0, 0, 15, 0, ENVELOPE_LINE) return img # ── Portal Field ─────────────────────────────────────────── # Translucent swirling-energy texture for the walk-through portal column. # Renders with alpha blending — the dark areas read as voids, the bright # center streaks read as concentrated portal energy. def portal_field() -> Image.Image: import math img = Image.new("RGBA", (16, 16), (0, 0, 0, 0)) cx, cy = 7.5, 7.5 for y in range(16): for x in range(16): dx = x - cx dy = y - cy dist = math.sqrt(dx * dx + dy * dy) angle = math.atan2(dy, dx) # swirl: angle modulated by distance swirl = math.sin(angle * 3 + dist * 1.5) * 0.5 + 0.5 # purple/violet base r = int(80 + swirl * 100) g = int(20 + swirl * 30) b = int(140 + swirl * 90) # alpha falls off near edges, bright in middle bands edge = max(0, 1 - dist / 8.5) alpha = int(160 * edge + swirl * 60) alpha = max(0, min(220, alpha)) img.putpixel((x, y), (r, g, b, alpha)) # Bright vertical core streaks for y in range(16): for x in (7, 8): r, g, b, _ = img.getpixel((x, y)) img.putpixel((x, y), (min(255, r + 60), min(255, g + 30), min(255, b + 60), 220)) return img # ── Redstone Link transmitter / receiver ─────────────────── # Machine faces, not icons. Following the mailbox lesson: the motif has to # reach the edges or a cube of it reads as a placeholder. Both share a gunmetal # plate with corner rivets and a beveled frame; the transmitter carries redstone # traces radiating OUT to all four edges, the receiver carries traces running IN # to a collector dish. Same silhouette, mirrored behaviour, different accent. LINK_PLATE = (62, 66, 74) LINK_PLATE_HL = (92, 97, 107) LINK_PLATE_SH = (38, 41, 47) LINK_RIVET = (140, 146, 158) TX_TRACE = (168, 30, 28) TX_TRACE_HOT = REDSTONE_BRIGHT TX_CORE = (255, 140, 110) RX_TRACE = (34, 96, 150) RX_TRACE_HOT = (92, 178, 240) RX_CORE = (200, 240, 255) def _link_plate() -> Image.Image: """Shared gunmetal base: beveled frame + corner rivets, fully opaque.""" img = Image.new("RGBA", (16, 16), LINK_PLATE) # Bevel: lit top/left, shadowed bottom/right rect(img, 0, 0, 15, 0, LINK_PLATE_HL) rect(img, 0, 0, 0, 15, LINK_PLATE_HL) rect(img, 0, 15, 15, 15, LINK_PLATE_SH) rect(img, 15, 0, 15, 15, LINK_PLATE_SH) # Corner rivets for cx, cy in ((2, 2), (13, 2), (2, 13), (13, 13)): px(img, cx, cy, LINK_RIVET) px(img, cx, cy + 1, LINK_PLATE_SH) return img def redstone_link_tx() -> Image.Image: img = _link_plate() # Traces running from the core out to all four edges: this is what makes a # cube of it read as wiring rather than a centred sprite. rect(img, 7, 0, 8, 15, TX_TRACE) rect(img, 0, 7, 15, 8, TX_TRACE) # Diagonal spurs toward the corners for i in range(3, 7): px(img, i, i, TX_TRACE) px(img, 15 - i, i, TX_TRACE) px(img, i, 15 - i, TX_TRACE) px(img, 15 - i, 15 - i, TX_TRACE) # Emitter core, hot centre rect(img, 6, 6, 9, 9, TX_TRACE_HOT) rect(img, 7, 7, 8, 8, TX_CORE) px(img, 7, 7, (255, 235, 220)) # Trace highlight so the cross reads as raised rect(img, 7, 1, 7, 5, TX_TRACE_HOT) rect(img, 1, 7, 5, 7, TX_TRACE_HOT) return img def redstone_link_rx() -> Image.Image: img = _link_plate() # Collector rings, broken at the axes so the in-running traces read clearly for x in range(3, 13): px(img, x, 3, RX_TRACE) px(img, x, 12, RX_TRACE) for y in range(3, 13): px(img, 3, y, RX_TRACE) px(img, 12, y, RX_TRACE) for x in range(5, 11): px(img, x, 5, RX_TRACE_HOT) px(img, x, 10, RX_TRACE_HOT) for y in range(5, 11): px(img, 5, y, RX_TRACE_HOT) px(img, 10, y, RX_TRACE_HOT) # Feed lines from the edges into the dish rect(img, 7, 0, 8, 2, RX_TRACE) rect(img, 7, 13, 8, 15, RX_TRACE) rect(img, 0, 7, 2, 8, RX_TRACE) rect(img, 13, 7, 15, 8, RX_TRACE) # Collector core rect(img, 7, 7, 8, 8, RX_TRACE_HOT) px(img, 7, 7, RX_CORE) px(img, 8, 8, RX_CORE) return img # ── Lobby portal blocks ──────────────────────────────────── # These previously pointed terrain_texture.json at vanilla paths # (emerald_block, amethyst_block, prismarine_bricks, end_portal_frame_top) # which a custom pack cannot resolve, so they rendered as missing-texture # once minecraft:geometry made material_instances take effect. Ship real # textures instead: a dark stone frame around a glowing field, one hue per # child, so the three destinations are distinguishable at a glance. PORTAL_STONE = (58, 60, 68) PORTAL_STONE_HL = (86, 89, 99) PORTAL_STONE_SH = (34, 35, 41) def _portal_face(core, bright, glow): img = Image.new("RGBA", (16, 16), PORTAL_STONE) # chiselled frame rect(img, 0, 0, 15, 0, PORTAL_STONE_HL) rect(img, 0, 0, 0, 15, PORTAL_STONE_HL) rect(img, 0, 15, 15, 15, PORTAL_STONE_SH) rect(img, 15, 0, 15, 15, PORTAL_STONE_SH) rect(img, 2, 2, 13, 13, PORTAL_STONE_SH) # glowing field rect(img, 3, 3, 12, 12, core) rect(img, 4, 4, 11, 11, bright) rect(img, 6, 6, 9, 9, glow) # corner sparks so the field reads as energy, not flat paint for cx, cy in ((4, 4), (11, 4), (4, 11), (11, 11)): px(img, cx, cy, glow) # dark centre seam rect(img, 7, 7, 8, 8, core) return img def portal_jamie(): return _portal_face((22, 92, 40), (46, 156, 66), (140, 240, 150)) def portal_lyla(): return _portal_face((78, 40, 130), (126, 74, 190), (214, 168, 255)) def portal_mya(): return _portal_face((22, 96, 104), (46, 152, 160), (150, 238, 244)) def portal_frame(): img = Image.new("RGBA", (16, 16), PORTAL_STONE) rect(img, 0, 0, 15, 0, PORTAL_STONE_HL) rect(img, 0, 0, 0, 15, PORTAL_STONE_HL) rect(img, 0, 15, 15, 15, PORTAL_STONE_SH) rect(img, 15, 0, 15, 15, PORTAL_STONE_SH) # inset panel with a dull gold ring, echoing an end portal frame rect(img, 3, 3, 12, 12, (48, 50, 57)) for x in range(4, 12): px(img, x, 4, GOLD); px(img, x, 11, GOLD) for y in range(4, 12): px(img, 4, y, GOLD); px(img, 11, y, GOLD) rect(img, 6, 6, 9, 9, (70, 66, 40)) px(img, 7, 7, GOLD_BRIGHT); px(img, 8, 8, GOLD_BRIGHT) return img # ── Naturalist Lite: three items shipped without icons ───── # frog_leg, cooked_frog_leg and snake_egg_block are declared in the BP and # mapped in item_texture.json, but the PNGs were never present, so they # rendered as missing-texture. Drawn to match the pack's existing style: # small sprite on transparency, muted natural palette, single highlight. FROG_RAW = (176, 122, 128) FROG_RAW_HI = (214, 164, 168) FROG_RAW_SH = (126, 82, 92) FROG_SKIN = (122, 148, 96) FROG_COOK = (156, 104, 56) FROG_COOK_HI = (198, 146, 88) FROG_COOK_SH = (104, 64, 32) BONE = (232, 226, 206) BONE_SH = (176, 170, 152) EGG_SHELL = (222, 214, 196) EGG_SHELL_HI = (244, 240, 228) EGG_SHELL_SH = (170, 162, 144) EGG_SPOT = (150, 138, 112) def _frog_leg(meat, hi, sh, skin=None): """Drumstick: meat mass upper-left, bone stub lower-right.""" img = Image.new("RGBA", (16, 16), (0, 0, 0, 0)) # meat mass rect(img, 4, 2, 10, 8, meat) rect(img, 3, 3, 3, 7, meat) rect(img, 11, 3, 11, 7, meat) rect(img, 5, 1, 9, 1, meat) rect(img, 5, 9, 9, 9, meat) # shading rect(img, 4, 8, 10, 9, sh) rect(img, 11, 4, 11, 7, sh) # highlight rect(img, 5, 2, 7, 3, hi) px(img, 5, 4, hi) # raw frog keeps a green tinge along the top contour rather than a patch, # so it reads as skin on the meat instead of a floating square if skin: for sx, sy in ((6, 1), (7, 1), (8, 1), (9, 2), (10, 3), (5, 2)): px(img, sx, sy, skin) px(img, 8, 2, (140, 166, 112)) # bone stub running to lower-right rect(img, 9, 10, 10, 11, BONE) rect(img, 11, 12, 12, 13, BONE) px(img, 12, 14, BONE) px(img, 10, 11, BONE_SH) px(img, 12, 13, BONE_SH) px(img, 13, 14, BONE_SH) return img def frog_leg(): return _frog_leg(FROG_RAW, FROG_RAW_HI, FROG_RAW_SH, FROG_SKIN) def cooked_frog_leg(): return _frog_leg(FROG_COOK, FROG_COOK_HI, FROG_COOK_SH) def snake_egg_block(): """A clutch of eggs, so it reads as the block form of the single egg item.""" img = Image.new("RGBA", (16, 16), (0, 0, 0, 0)) def egg(cx, cy, w, h): rect(img, cx, cy, cx + w, cy + h, EGG_SHELL) rect(img, cx, cy + h, cx + w, cy + h, EGG_SHELL_SH) rect(img, cx + w, cy + 1, cx + w, cy + h, EGG_SHELL_SH) px(img, cx + 1, cy + 1, EGG_SHELL_HI) egg(2, 6, 4, 6) egg(9, 5, 4, 6) egg(5, 8, 4, 5) # speckles for sx, sy in ((3, 9), (11, 8), (6, 11), (4, 7), (12, 10)): px(img, sx, sy, EGG_SPOT) return img def main() -> None: save(smart_crafting_table(), "smart-crafting-addon/smart_crafting_RP/textures/blocks/smart_crafting_table.png") save(post_office_block(), "postal-service-addon/postal_service_RP/textures/blocks/post_office.png") save(mailbox_block(), "postal-service-addon/postal_service_RP/textures/blocks/mailbox.png") save(tent_canvas(), "camping-supplies-addon/camping_supplies_RP/textures/blocks/tent_canvas.png") save(portal_field(), "lobby-addon/lobby_transfer_RP/textures/blocks/portal_field.png") save(portal_frame(), "lobby-addon/lobby_transfer_RP/textures/blocks/portal_frame.png") save(portal_jamie(), "lobby-addon/lobby_transfer_RP/textures/blocks/portal_jamie.png") save(portal_lyla(), "lobby-addon/lobby_transfer_RP/textures/blocks/portal_lyla.png") save(portal_mya(), "lobby-addon/lobby_transfer_RP/textures/blocks/portal_mya.png") save(redstone_link_tx(), "redstone-link-addon/redstone_link_RP/textures/blocks/redstone_link_tx.png") save(redstone_link_rx(), "redstone-link-addon/redstone_link_RP/textures/blocks/redstone_link_rx.png") NAT = "naturalist-lite-addon/naturalist_lite_RP/textures/sf/nba/items/" save(frog_leg(), NAT + "frog_leg.png") save(cooked_frog_leg(), NAT + "cooked_frog_leg.png") save(snake_egg_block(), NAT + "snake_egg_block.png") if __name__ == "__main__": main()