Integrate verified Sanctuary beta.110 with clay workshop, eggs and seasonal snow
Build Sanctuary / build (push) Canceled after 0s
Build Sanctuary / build (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
{
|
||||
"white": {
|
||||
"brick": [
|
||||
160,
|
||||
155,
|
||||
163
|
||||
],
|
||||
"clay": [
|
||||
198,
|
||||
196,
|
||||
200
|
||||
],
|
||||
"source_sha256": "67ede486baa239fcb86f8f01dd9fa07d60e7ef9e64999dcf098359585223fda3"
|
||||
},
|
||||
"orange": {
|
||||
"brick": [
|
||||
187,
|
||||
96,
|
||||
33
|
||||
],
|
||||
"clay": [
|
||||
211,
|
||||
170,
|
||||
141
|
||||
],
|
||||
"source_sha256": "8bfa041d13a01c042131e66c074eb79191dc034fc99a3a58ee6b17773cb17441"
|
||||
},
|
||||
"magenta": {
|
||||
"brick": [
|
||||
187,
|
||||
72,
|
||||
182
|
||||
],
|
||||
"clay": [
|
||||
211,
|
||||
159,
|
||||
208
|
||||
],
|
||||
"source_sha256": "7e3de34f443ac6ffe22ad18abc92ed65250109eec140e43106c88911ab57d4c5"
|
||||
},
|
||||
"light_blue": {
|
||||
"brick": [
|
||||
42,
|
||||
111,
|
||||
168
|
||||
],
|
||||
"clay": [
|
||||
145,
|
||||
176,
|
||||
202
|
||||
],
|
||||
"source_sha256": "a617f1226fc81b162aa52a5b490017220e51cb01d475b656bb078cfe427ac6d2"
|
||||
},
|
||||
"yellow": {
|
||||
"brick": [
|
||||
163,
|
||||
143,
|
||||
56
|
||||
],
|
||||
"clay": [
|
||||
200,
|
||||
191,
|
||||
152
|
||||
],
|
||||
"source_sha256": "d5212ed932c1cf5430dec2ff2e324ea8c9e0a3d4940c4600255ca406c7af7492"
|
||||
},
|
||||
"lime": {
|
||||
"brick": [
|
||||
78,
|
||||
159,
|
||||
61
|
||||
],
|
||||
"clay": [
|
||||
162,
|
||||
198,
|
||||
154
|
||||
],
|
||||
"source_sha256": "0aa80fd773294deb6edf6756b34fd4aec9aad65f24933d59ec595d26198ee4e8"
|
||||
},
|
||||
"pink": {
|
||||
"brick": [
|
||||
204,
|
||||
154,
|
||||
209
|
||||
],
|
||||
"clay": [
|
||||
218,
|
||||
196,
|
||||
221
|
||||
],
|
||||
"source_sha256": "2d197f8c27150c59b4cafdb568a77e1e9a6d2377790ec39626506b24bbe3af58"
|
||||
},
|
||||
"gray": {
|
||||
"brick": [
|
||||
88,
|
||||
90,
|
||||
99
|
||||
],
|
||||
"clay": [
|
||||
116,
|
||||
118,
|
||||
125
|
||||
],
|
||||
"source_sha256": "146248d1c67977e9cd667c592ca7b1905e5fd4c08b719cc83df3b70dac724e2b",
|
||||
"clay_contrast": 1.35
|
||||
},
|
||||
"light_gray": {
|
||||
"brick": [
|
||||
94,
|
||||
92,
|
||||
100
|
||||
],
|
||||
"clay": [
|
||||
169,
|
||||
168,
|
||||
172
|
||||
],
|
||||
"source_sha256": "22ed4652ff235d16a7fcdebc870516280480fef0fd15a11866dd2bde6a2cff8d"
|
||||
},
|
||||
"cyan": {
|
||||
"brick": [
|
||||
92,
|
||||
156,
|
||||
148
|
||||
],
|
||||
"clay": [
|
||||
168,
|
||||
197,
|
||||
193
|
||||
],
|
||||
"source_sha256": "65b9d6aea4c75597d33f85640f36dc904004ad82556a227393de587deaece29d"
|
||||
},
|
||||
"purple": {
|
||||
"brick": [
|
||||
142,
|
||||
42,
|
||||
223
|
||||
],
|
||||
"clay": [
|
||||
190,
|
||||
145,
|
||||
227
|
||||
],
|
||||
"source_sha256": "6e0f71dbdbcb1dc960799030d3faaefa59d266d979e94ffe739163c589326420"
|
||||
},
|
||||
"blue": {
|
||||
"brick": [
|
||||
74,
|
||||
89,
|
||||
136
|
||||
],
|
||||
"clay": [
|
||||
160,
|
||||
167,
|
||||
188
|
||||
],
|
||||
"source_sha256": "4ddfe1960668269014c1be6c40208a6d65f3c053d4a29a870751f1843db43fb7"
|
||||
},
|
||||
"brown": {
|
||||
"brick": [
|
||||
83,
|
||||
60,
|
||||
41
|
||||
],
|
||||
"clay": [
|
||||
164,
|
||||
154,
|
||||
145
|
||||
],
|
||||
"source_sha256": "e7b8c560cd24031219d753eaa5abc658edc6a4485977efaf986097f872abab0c"
|
||||
},
|
||||
"green": {
|
||||
"brick": [
|
||||
75,
|
||||
118,
|
||||
59
|
||||
],
|
||||
"clay": [
|
||||
160,
|
||||
180,
|
||||
153
|
||||
],
|
||||
"source_sha256": "6af83f7e1a8c42e32abbf381471ace1bc7c315a2eedbf9361b70002ce79a30d7"
|
||||
},
|
||||
"red": {
|
||||
"brick": [
|
||||
118,
|
||||
61,
|
||||
59
|
||||
],
|
||||
"clay": [
|
||||
180,
|
||||
154,
|
||||
153
|
||||
],
|
||||
"source_sha256": "a0feb57b088fa8d9fc94adfcdbe5bbe9c00bcb4bd8225e781c06c28d9db61934"
|
||||
},
|
||||
"black": {
|
||||
"brick": [
|
||||
50,
|
||||
51,
|
||||
47
|
||||
],
|
||||
"clay": [
|
||||
68,
|
||||
69,
|
||||
65
|
||||
],
|
||||
"source_sha256": "6600aa4c16a5faf63188e8da6c5c39b1aa28c309171fd5bccc29ed2283dee0f5",
|
||||
"clay_contrast": 1.35
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[[9, 19, 23], [9, 25, 26], [10, 19, 23], [10, 25, 26], [11, 16, 17], [11, 18, 31], [12, 13, 32], [12, 34, 35], [13, 13, 35], [14, 12, 36], [15, 12, 36], [16, 11, 37], [17, 10, 37], [18, 10, 38], [19, 10, 38], [30, 19, 20], [30, 23, 24], [30, 26, 29], [31, 16, 30], [31, 31, 32], [32, 14, 34], [32, 35, 36], [33, 14, 34], [33, 35, 36], [34, 13, 36], [35, 11, 37], [36, 11, 37], [37, 10, 38], [38, 10, 38], [39, 10, 38], [40, 10, 38], [41, 10, 19], [41, 20, 24], [41, 26, 29], [41, 30, 38]]
|
||||
@@ -0,0 +1,103 @@
|
||||
"""Native 26.3 resources + author-approved deterministic vanilla pixel recoloring.
|
||||
Requires Pillow. Source brick textures already installed in assets/sanctuary/textures/block.
|
||||
Usage: python generate-colored-bricks.py --minecraft-jar <26.3 minecraft-client.jar>
|
||||
"""
|
||||
import argparse, hashlib, json, statistics, zipfile
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageDraw
|
||||
ap=argparse.ArgumentParser();ap.add_argument('--minecraft-jar',required=True);args=ap.parse_args()
|
||||
root=Path(__file__).resolve().parents[1];res=root/'mods/sanctuary/src/main/resources';assets=res/'assets/sanctuary';data=res/'data'
|
||||
colors=['white','orange','magenta','light_blue','yellow','lime','pink','gray','light_gray','cyan','purple','blue','brown','green','red','black']
|
||||
fr=[('blanche','blanches'),('orange','orange'),('magenta','magenta'),('bleu clair','bleu clair'),('jaune','jaunes'),('vert clair','vert clair'),('rose','roses'),('grise','grises'),('gris clair','gris clair'),('cyan','cyan'),('violette','violettes'),('bleue','bleues'),('marron','marron'),('verte','vertes'),('rouge','rouges'),('noire','noires')]
|
||||
z=zipfile.ZipFile(args.minecraft_jar)
|
||||
def write(path,obj):
|
||||
path.parent.mkdir(parents=True,exist_ok=True);path.write_text(json.dumps(obj,ensure_ascii=False,indent=2)+'\n')
|
||||
def native(path):return json.loads(z.read(path))
|
||||
def copy_native(path,dest,mapping):
|
||||
text=z.read(path).decode()
|
||||
for a,b in sorted(mapping.items(),key=lambda x:-len(x[0])):text=text.replace(a,b)
|
||||
write(dest,json.loads(text))
|
||||
def id(name):return 'sanctuary:'+name
|
||||
def luminance(p):return .2126*p[0]+.7152*p[1]+.0722*p[2]
|
||||
def sample(image):
|
||||
pixels=[p[:3] for p in image.convert('RGBA').getdata() if p[3]]
|
||||
chroma=[max(p)-min(p) for p in pixels]
|
||||
if max(chroma)>20:
|
||||
threshold=sorted(chroma)[len(chroma)//2];pixels=[p for p in pixels if max(p)-min(p)>=threshold]
|
||||
else:
|
||||
threshold=sorted(map(luminance,pixels))[int(len(pixels)*.7)];pixels=[p for p in pixels if luminance(p)<=threshold]
|
||||
return tuple(round(statistics.mean(p[i] for p in pixels)) for i in range(3))
|
||||
def recolor(src,target,contrast=.85):
|
||||
image=Image.open(__import__('io').BytesIO(z.read('assets/minecraft/textures/'+src+'.png'))).convert('RGBA')
|
||||
pixels=list(image.getdata());mean=statistics.mean(luminance(p) for p in pixels if p[3])
|
||||
out=[]
|
||||
for p in pixels:
|
||||
if not p[3]:out.append(p);continue
|
||||
# Retain every source shading step and alpha, never resize or redraw a pixel.
|
||||
delta=luminance(p)-mean
|
||||
out.append(tuple(max(0,min(255,round(c+delta*contrast))) for c in target)+(p[3],))
|
||||
image.putdata(out);return image
|
||||
recipes=[];block_ids=[];item_ids=[];palette={}
|
||||
def tag(namespace,kind,name,values):
|
||||
path=data/namespace/'tags'/kind/(name+'.json');old=json.loads(path.read_text()) if path.exists() else {'replace':False,'values':[]}
|
||||
old['values']=list(dict.fromkeys(old['values']+values));write(path,old)
|
||||
def recipe(name,obj,ingredient):
|
||||
write(data/'sanctuary/recipe'/(name+'.json'),obj);recipes.append(id(name))
|
||||
write(data/'sanctuary/advancement/recipes/colored_bricks'/(name+'.json'),{'parent':'minecraft:recipes/root','criteria':{'has_material':{'trigger':'minecraft:inventory_changed','conditions':{'items':[{'items':ingredient}]}},'has_the_recipe':{'trigger':'minecraft:recipe_unlocked','conditions':{'recipes':id(name)}}},'requirements':[['has_material','has_the_recipe']],'rewards':{'recipes':[id(name)]}})
|
||||
def shaped(name,pattern,key,result,count=1):recipe(name,{'type':'minecraft:crafting_shaped','category':'building','pattern':pattern,'key':key,'result':{'id':result,'count':count}},list(key.values())[0])
|
||||
labels={lang:json.loads((assets/'lang'/f'{lang}.json').read_text()) for lang in ['fr_fr','en_us']}
|
||||
version=dict(line.split('=',1) for line in (root/'gradle.properties').read_text().splitlines() if '=' in line and not line.startswith('#'))['pack_version']
|
||||
preview=Image.new('RGB',(840,16*68+50),(30,31,34));draw=ImageDraw.Draw(preview);draw.text((12,12),version.upper()+' bricks / clay block / clay ball / brick item - native 16 x 16',fill='white')
|
||||
for index,color in enumerate(colors):
|
||||
names=[color+'_'+suffix for suffix in ['bricks','brick_slab','brick_stairs','clay','clay_ball','brick']];bricks,slab,stairs,clay,ball,brick=names
|
||||
source=assets/'textures/block'/f'{bricks}.png';image=Image.open(source);assert image.size==(16,16),source
|
||||
target=sample(image)
|
||||
# Dark neutrals need less white to stay distinct from light gray; retain the source hue.
|
||||
weight={'gray':.80,'black':.90}.get(color,.45)
|
||||
pastel=tuple(round(c*weight+230*(1-weight)) for c in target)
|
||||
clay_contrast=1.35 if color in ('gray','black') else .85
|
||||
palette[color]={'brick':target,'clay':pastel,'source_sha256':hashlib.sha256(source.read_bytes()).hexdigest()}
|
||||
if color in ('gray','black'):palette[color]['clay_contrast']=clay_contrast
|
||||
images=[image.convert('RGBA')]
|
||||
for src,name,tint in [('block/clay',clay,pastel),('item/clay_ball',ball,pastel),('item/brick',brick,target)]:
|
||||
out=recolor(src,tint,clay_contrast if src in ('block/clay','item/clay_ball') else .85);path=assets/'textures'/src.split('/')[0]/(name+'.png');path.parent.mkdir(parents=True,exist_ok=True);out.save(path);images.append(out)
|
||||
draw.text((12,50+index*68+22),color,fill='white')
|
||||
for col,img in enumerate(images):
|
||||
preview.paste(img.resize((64,64),Image.Resampling.NEAREST),(170+col*160,50+index*68),img.resize((64,64),Image.Resampling.NEAREST))
|
||||
mapping={f'minecraft:{s}':id(n) for s,n in zip(['bricks','brick_slab','brick_stairs','clay','clay_ball','brick'],names)}
|
||||
mapping.update({f'minecraft:block/{s}':f'sanctuary:block/{n}' for s,n in zip(['bricks','brick_slab','brick_stairs','clay'],names)})
|
||||
mapping.update({f'minecraft:blocks/{s}':f'sanctuary:blocks/{n}' for s,n in zip(['bricks','brick_slab','brick_stairs','clay'],names)})
|
||||
mapping.update({f'minecraft:item/{s}':f'sanctuary:item/{n}' for s,n in [('clay_ball',ball),('brick',brick)]})
|
||||
for vanilla,name in zip(['bricks','brick_slab','brick_stairs','clay'],names):
|
||||
for category in ['blockstates','models/block','items']:
|
||||
copy_native('assets/minecraft/'+category+'/'+vanilla+'.json',assets/category/(name+'.json'),mapping)
|
||||
copy_native('data/minecraft/loot_table/blocks/'+vanilla+'.json',data/'sanctuary/loot_table/blocks'/(name+'.json'),mapping)
|
||||
for vanilla,name in [('brick_slab_top',slab+'_top'),('brick_stairs_inner',stairs+'_inner'),('brick_stairs_outer',stairs+'_outer')]:
|
||||
copy_native('assets/minecraft/models/block/'+vanilla+'.json',assets/'models/block'/(name+'.json'),mapping)
|
||||
for vanilla,name in [('clay_ball',ball),('brick',brick)]:
|
||||
for category in ['models/item','items']:copy_native('assets/minecraft/'+category+'/'+vanilla+'.json',assets/category/(name+'.json'),mapping)
|
||||
block_ids.extend(map(id,names[:4]));item_ids.extend(map(id,names));
|
||||
singular,plural=fr[index];en=color.replace('_',' ').title()
|
||||
for key,eng,french,isblock in zip(names,[f'{en} Bricks',f'{en} Brick Slab',f'{en} Brick Stairs',f'{en} Clay',f'{en} Clay Ball',f'{en} Brick'],[f'Briques {plural}',f'Dalle de briques {plural}',f'Escalier de briques {plural}',f'Argile {singular}',f"Boule d’argile {singular}",f'Brique {singular}'],[True]*4+[False]*2):
|
||||
translation=('block.' if isblock else 'item.')+'sanctuary.'+key;labels['en_us'][translation]=eng;labels['fr_fr'][translation]=french
|
||||
dye='minecraft:'+color+'_dye'
|
||||
for output,ingredient in [(ball,'#sanctuary:clay_balls'),(clay,'#sanctuary:clay_blocks'),(brick,'#sanctuary:brick_items'),(bricks,'#sanctuary:brick_blocks')]:
|
||||
shaped(output+'_from_dye',['###','#X#','###'],{'#':ingredient,'X':dye},id(output),8)
|
||||
shaped(clay,['##','##'],{'#':id(ball)},id(clay));shaped(bricks,['##','##'],{'#':id(brick)},id(bricks))
|
||||
shaped(slab,['###'],{'#':id(bricks)},id(slab),6);shaped(stairs,['# ','## ','###'],{'#':id(bricks)},id(stairs),4)
|
||||
for output,amount in [(slab,2),(stairs,1)]:recipe(output+'_from_stonecutting',{'type':'minecraft:stonecutting','ingredient':id(bricks),'result':{'id':id(output),'count':amount}},id(bricks))
|
||||
for output,ingredient,exp in [(id(brick),ball,.3),('minecraft:'+color+'_terracotta',clay,.35)]:
|
||||
recipe(ingredient+'_smelting',{'type':'minecraft:smelting','cookingtime':200,'experience':exp,'ingredient':id(ingredient),'result':{'id':output}},id(ingredient))
|
||||
tag('minecraft','block','mineable/pickaxe',list(map(id,names[:3])));tag('minecraft','block','mineable/shovel',[id(clay)])
|
||||
for kind in ['block','item']:
|
||||
tag('minecraft',kind,'slabs',[id(slab)]);tag('minecraft',kind,'stairs',[id(stairs)])
|
||||
for name,values in [('clay_balls',['minecraft:clay_ball',id(ball)]),('clay_blocks',['minecraft:clay',id(clay)]),('brick_items',['minecraft:brick',id(brick)]),('brick_blocks',['minecraft:bricks',id(bricks)])]:tag('sanctuary','item',name,values)
|
||||
for lang,obj in labels.items():write(assets/'lang'/f'{lang}.json',obj)
|
||||
p=root/'scripts/data/collections-sanctuary.json';obj=json.loads(p.read_text());obj['clay_and_bricks']={'additional_recipes':recipes,'additional_items':item_ids,'members':{'blocks':block_ids,'items':item_ids}};write(p,obj)
|
||||
# The reviewed collection compiler remains the sole writer of runtime taxonomy.
|
||||
import subprocess,sys
|
||||
subprocess.run([sys.executable,str(root/'scripts/compile_collections.py'),'--write'],check=True)
|
||||
write(root/'tools/colored-bricks-palette.json',palette)
|
||||
(root/'build').mkdir(exist_ok=True)
|
||||
preview.save(root/'build'/f'colored-bricks-{version}-preview.png')
|
||||
print(f'{len(colors)} colors, {len(block_ids)} blocks, {len(item_ids)} items including blocks, {len(recipes)} recipes')
|
||||
@@ -2,7 +2,9 @@
|
||||
No image resampling: JSON UVs select thirds of the supplied source PNGs.
|
||||
"""
|
||||
import json
|
||||
import copy
|
||||
from pathlib import Path
|
||||
embers = json.loads(Path(__file__).with_name('fourneau-embers.json').read_text())
|
||||
root = Path(__file__).resolve().parents[1] / 'mods/sanctuary/src/main/resources/assets/sanctuary/models/block/fourneau'
|
||||
root.mkdir(parents=True, exist_ok=True)
|
||||
for facing in ('north', 'east', 'south', 'west'):
|
||||
@@ -16,3 +18,24 @@ for facing in ('north', 'east', 'south', 'west'):
|
||||
model = {'textures':{n:'sanctuary:block/fourneau/'+n for n in ('front','side','top')} | {'particle':'sanctuary:block/fourneau/side'},
|
||||
'elements':[{'from':[0,0,0],'to':[16,16,16],'faces':faces}]}
|
||||
(root / f'{facing}_{x}_{y}_{z}.json').write_text(json.dumps(model,indent=2)+'\n')
|
||||
# Preserve every original masonry pixel. Only the dark aperture strips
|
||||
# receive the generated fire artwork, slightly ahead of the native face.
|
||||
lit = copy.deepcopy(model)
|
||||
lit['textures']['embers'] = 'sanctuary:block/fourneau/front_on'
|
||||
front = {'north': z == 0, 'south': z == 2, 'east': x == 2, 'west': x == 0}[facing]
|
||||
u0 = {'north': 2-x, 'south': x, 'east': 2-z, 'west': z}[facing]*16
|
||||
v0 = (2-y)*16
|
||||
if front:
|
||||
for row, start, end in embers:
|
||||
lo, hi = max(start,u0), min(end,u0+16)
|
||||
if not v0 <= row < v0+16 or lo >= hi:
|
||||
continue
|
||||
a,b = lo-u0,hi-u0
|
||||
bottom,top = 15-(row-v0),16-(row-v0)
|
||||
if facing == 'north': begin,finish = [16-b,bottom,-.002],[16-a,top,-.002]
|
||||
elif facing == 'south': begin,finish = [a,bottom,16.002],[b,top,16.002]
|
||||
elif facing == 'east': begin,finish = [16.002,bottom,16-b],[16.002,top,16-a]
|
||||
else: begin,finish = [-.002,bottom,a],[-.002,top,b]
|
||||
lit['elements'].append({'from':begin,'to':finish,'faces':{facing:{
|
||||
'texture':'#embers','cullface':facing,'uv':[lo/3,row/3,hi/3,(row+1)/3]}}})
|
||||
(root / f'{facing}_{x}_{y}_{z}_lit.json').write_text(json.dumps(lit,indent=2)+'\n')
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
"""Tile the creator's 48x48 top and 48x16 side, without resampling either PNG."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
root=Path(__file__).resolve().parents[1]/'mods/sanctuary/src/main/resources/assets/sanctuary'
|
||||
models=root/'models/block/metatable';models.mkdir(parents=True,exist_ok=True)
|
||||
variants={}
|
||||
for z in range(3):
|
||||
for x in range(3):
|
||||
part=x+3*z;faces={}
|
||||
for d,u in [('north',2-x),('south',x),('east',2-z),('west',z)]:
|
||||
faces[d]={'texture':'#side','cullface':d,'uv':[u*16/3,0,(u+1)*16/3,16]}
|
||||
faces['up']={'texture':'#top','cullface':'up','uv':[x*16/3,z*16/3,(x+1)*16/3,(z+1)*16/3]}
|
||||
faces['down']={'texture':'#bottom','cullface':'down','uv':[0,0,16,16]}
|
||||
model={'textures':{'top':'sanctuary:block/metatable/top','side':'sanctuary:block/metatable/side','bottom':'minecraft:block/oak_planks','particle':'sanctuary:block/metatable/side'},'elements':[{'from':[0,0,0],'to':[16,16,16],'faces':faces}]}
|
||||
(models/f'{part}.json').write_text(json.dumps(model,indent=2)+'\n')
|
||||
variants[f'part={part}']={'model':f'sanctuary:block/metatable/{part}'}
|
||||
(root/'blockstates/metatable.json').write_text(json.dumps({'variants':variants},indent=2)+'\n')
|
||||
@@ -18,7 +18,15 @@ def sides(x,y,thin=False,extended=False):
|
||||
for d,u,r in [('up',x,0),('down',2-x,180),('west',y,270),('east',2-y,90)]:
|
||||
result[d]=face('side',[u*16/3,4 if extended else 0,(u+1)*16/3,4 if thin else 16],r,None if thin else d)
|
||||
return result
|
||||
def shaft():return {'from':[2,2,0],'to':[14,14,16],'faces':{d:face('top',[6,0,10,16]) for d in rotations}}
|
||||
def shaft(start=0,end=16):
|
||||
# Use only the central 16px wood tile of the 48px plate, at native pixel
|
||||
# density. Short base/head segments sample only their actual length.
|
||||
faces={}
|
||||
for d in rotations:
|
||||
pixels=([2,2,14,14] if d in ('north','south') else
|
||||
[2,start,14,end] if d in ('up','down') else [start,2,end,14])
|
||||
faces[d]=face('top',[(16+p)/3 for p in pixels])
|
||||
return {'from':[2,2,start],'to':[14,14,end],'faces':faces}
|
||||
for part in range(9):
|
||||
x,y=part%3,part//3
|
||||
for front in ['top','top_sticky','inner']:
|
||||
@@ -26,13 +34,13 @@ for part in range(9):
|
||||
faces=sides(x,y,extended=extended);faces['north']=face(front,uv(2-x,2-y),cull=None if extended else 'north');faces['south']=face('bottom',uv(x,2-y),cull='south')
|
||||
pieces=[{'from':[0,0,4 if extended else 0],'to':[16,16,16],'faces':faces}]
|
||||
if extended and part==4:
|
||||
rod=shaft();rod['to'][2]=4;pieces.append(rod)
|
||||
pieces.append(shaft(0,4))
|
||||
write(f'base_{front}_{part}',pieces)
|
||||
for sticky in [False,True]:
|
||||
faces=sides(x,y,True);faces['north']=face('top_sticky' if sticky else 'top',uv(2-x,2-y));faces['south']=face('top',uv(x,2-y))
|
||||
pieces=[{'from':[0,0,0],'to':[16,16,4],'faces':faces}]
|
||||
if part==4:
|
||||
rod=shaft();rod['from'][2]=4;pieces.append(rod)
|
||||
pieces.append(shaft(4,16))
|
||||
write(f'head_{str(sticky).lower()}_{part}',pieces)
|
||||
write('rod',[shaft()])
|
||||
(root/'blockstates').mkdir(parents=True,exist_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user