# -*- coding: utf-8 -*- """把 box_of_nails.bbmodel 转换为网易自定义方块模型(netease:block_geometry)。 转换规则(与官方 CustomBlocksMod 示例的 bbmodel->json 实测结果一致): cube.origin = [-to.x, from.y, from.z] cube.size = to - from cube.pivot = [-bb.origin.x, bb.origin.y, bb.origin.z] cube.rotation / bone.rotation = [-rx, -ry, rz] uv: up 面 -> uv=[x2,y2], uv_size=[x1-x2, y1-y2] 其余面 -> uv=[x1,y1], uv_size=[x2-x1, y2-y1] 负的 uv_size 表示贴图镜像(与原格式一致) 贴图为空(texture=null 或零面积)的面不输出 """ import base64 import json import os ROOT = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02" RES = os.path.join(ROOT, "resource_pack_t7eJjrxY") SRC = r"c:\Users\30272\.trae-cn\attachments\6ac7514c01a7d726cbee7358\7dc21437-b0c4-442b-a225-1ce20d2bdbbc_593d488a-acae-4a41-a007-98367aec6727_box_of_nails.bbmodel" TEX_NAME = "box_of_nails" TEX_KEY = "dn_sa_" + TEX_NAME MODEL_ID = "dn_sa:" + TEX_NAME + "_model" BONE_NAME = "bone" FACE_ORDER = ("north", "east", "south", "west", "up", "down") def num(v): if isinstance(v, float): if v.is_integer(): return int(v) return round(v, 4) return v def arr(v): return "[" + ", ".join(str(num(x)) for x in v) + "]" def conv_uv(el): out = [] for face in FACE_ORDER: f = el["faces"].get(face) if not f or f.get("texture") is None: continue x1, y1, x2, y2 = f["uv"] if x1 == x2 or y1 == y2: continue if face == "up": entry = "{" + '"uv": %s, "uv_size": %s' % (arr([x2, y2]), arr([x1 - x2, y1 - y2])) else: entry = "{" + '"uv": %s, "uv_size": %s' % (arr([x1, y1]), arr([x2 - x1, y2 - y1])) if f.get("rotation"): entry += ', "rot": %s' % num(f["rotation"]) entry += "}" out.append('"%s": %s' % (face, entry)) return out def main(): with open(SRC, "r", encoding="utf-8") as fp: bb = json.load(fp) tex = bb["textures"][0] tw, th = tex["width"], tex["height"] # 1) 贴图 -> resourcepack/textures/blocks raw = base64.b64decode(tex["source"].split(",", 1)[1]) tex_dir = os.path.join(RES, "textures", "blocks") os.makedirs(tex_dir, exist_ok=True) tex_path = os.path.join(tex_dir, TEX_NAME + ".png") with open(tex_path, "wb") as fp: fp.write(raw) # 2) 模型 -> resourcepack/models/netease_block cube_blocks = [] for el in bb["elements"]: lines = [] lines.append("\t\t\t\t\t{") body = [] body.append('"origin": %s' % arr([-el["to"][0], el["from"][1], el["from"][2]])) body.append('"size": %s' % arr([el["to"][i] - el["from"][i] for i in range(3)])) if el.get("rotation"): body.append('"pivot": %s' % arr([-el["origin"][0], el["origin"][1], el["origin"][2]])) body.append('"rotation": %s' % arr([-el["rotation"][0], -el["rotation"][1], el["rotation"][2]])) uv_lines = conv_uv(el) txt = ",\n".join("\t\t\t\t\t\t%s" % b for b in body) txt += ',\n\t\t\t\t\t\t"uv": {\n' txt += ",\n".join("\t\t\t\t\t\t\t%s" % u for u in uv_lines) txt += "\n\t\t\t\t\t\t}" lines.append(txt) lines.append("\t\t\t\t\t}") cube_blocks.append("\n".join(lines)) model = [] model.append("{") model.append('\t"format_version": "1.13.0",') model.append('\t"netease:block_geometry": {') model.append('\t\t"description": {') model.append('\t\t\t"identifier": "%s",' % MODEL_ID) model.append('\t\t\t"textures": ["%s"],' % TEX_KEY) model.append('\t\t\t"textures_descriptions": [') model.append('\t\t\t\t{ "width": %d, "length": %d }' % (tw, th)) model.append('\t\t\t],') model.append('\t\t\t"use_ao": true') model.append('\t\t},') model.append('\t\t"bones": [') model.append('\t\t\t{') model.append('\t\t\t\t"name": "%s",' % BONE_NAME) model.append('\t\t\t\t"pivot": [0, 0, 0],') model.append('\t\t\t\t"cubes": [') model.append(",\n".join(cube_blocks)) model.append('\t\t\t\t]') model.append('\t\t\t}') model.append('\t\t]') model.append('\t}') model.append('}') text = "\n".join(model) + "\n" model_dir = os.path.join(RES, "models", "netease_block") os.makedirs(model_dir, exist_ok=True) model_path = os.path.join(model_dir, TEX_KEY + ".json") with open(model_path, "w", encoding="utf-8", newline="\n") as fp: fp.write(text) print("texture ->", tex_path) print("model ->", model_path) print("identifier:", MODEL_ID, "| terrain_texture key:", TEX_KEY, "| %dx%d" % (tw, th)) print("cubes:", len(bb["elements"])) if __name__ == "__main__": main()