497 lines
20 KiB
Python
497 lines
20 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""救护车一次性生成器 (v3,支持多车型):
|
||
对 CARS 里的每个车型:
|
||
1) 依据其源模型(用户原始模型,已按网易规则做过 X 镜像)逐立方体做层级变换,
|
||
得到世界空间 AABB。关键:网易方块实体的渲染映射为 world = (-geo_x/16, geo_y/16, geo_z/16),
|
||
即 X 轴镜像;因此碰撞检测必须使用镜像后的世界坐标。
|
||
2) 对 4 个车体旋转角 φ(0/90/180/270) 分别求「每格与车体的交集 AABB」,量化到 1/QUANT 格并去重;
|
||
几何体根骨骼 Y 角设为 90 - φ(才能得到世界旋转 φ),并把整车居中到主方块中心、车底贴地。
|
||
3) 生成:每个车型一份预旋转几何体(4 条,按朝向)、4 个主方块 + 若干形状共享占位方块;
|
||
汇总生成 blocks.json、terrain_texture.json,并把布局数据写入 ambulanceServer.py 末尾。
|
||
|
||
车型命名规则(tag):
|
||
主方块 dn_sa:<tag>_main_<yaw>
|
||
占位方块 dn_sa:<tag>_ph_<NN> (形状共享,仅提供碰撞)
|
||
几何体 geometry.dn_sa_<tag>_<yaw> -> resource_pack/models/entity/<tag>_geo.json
|
||
client_entity entity/<tag>_main_<yaw>_block_entity.json
|
||
"""
|
||
import json
|
||
import math
|
||
import os
|
||
import io
|
||
|
||
ROOT = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02"
|
||
BP = os.path.join(ROOT, "behavior_pack_kcH4M5u0")
|
||
RP = os.path.join(ROOT, "resource_pack_t7eJjrxY")
|
||
BEH_BLOCKS_DIR = os.path.join(BP, "netease_blocks")
|
||
ENTITY_DIR = os.path.join(RP, "entity")
|
||
MODELS_DIR = os.path.join(RP, r"models\entity")
|
||
|
||
# ---------------------------------------------------------------- 车型配置
|
||
# tag 决定所有资源的命名;src 是源模型;tex 是该车的整车贴图(client_entity 用)
|
||
CARS = [
|
||
{
|
||
"item": "dn_sa:ambulance_car",
|
||
"tag": "ambulance_car",
|
||
"src": os.path.join(ROOT, "_gen_amb_src.geo.json"),
|
||
"tex": "textures/blocks/ambulance_car",
|
||
},
|
||
{
|
||
"item": "dn_sa:ambulance_car_broken",
|
||
"tag": "ambulance_car_broken",
|
||
"src": os.path.join(ROOT, "_gen_amb_src_broken.geo.json"),
|
||
"tex": "textures/blocks/ambulance_broken",
|
||
},
|
||
{
|
||
"item": "dn_sa:ambulance_car_destroyed",
|
||
"tag": "ambulance_car_destroyed",
|
||
"src": os.path.join(ROOT, "_gen_amb_src_destroyed.geo.json"),
|
||
"tex": "textures/blocks/ambulance_destroyed",
|
||
},
|
||
]
|
||
|
||
# 模型原点(0,0,0) 对应的主方块格上的位置(最小角)。若游戏内整车整体偏移,改这里即可。
|
||
ANCHOR = (0.0, 0.0, 0.0)
|
||
QUANT = 8 # 碰撞盒量化精度:1/8 格(约 2 个贴图像素)
|
||
YAWS = (0, 90, 180, 270) # 车体在世界空间的旋转角 φ(几何体根骨骼 Y 角 = 90 - φ)
|
||
|
||
# 玩家朝向象限(0=南+Z,90=西-X,180=北-Z,270=东+X) -> 车体世界旋转角 φ
|
||
# 依据:φ=0 时车头(capo)朝 -X;把 -X 经 Ry(φ) 转到玩家朝向
|
||
EXTRA_BY_FACING = {0: 90, 90: 0, 180: 270, 270: 180}
|
||
|
||
# 「车体局部格」(φ=0 坐标系,相对主方块的偏移) —— 这些格子不生成占位方块。
|
||
# 1) 挡风玻璃前上方 / 引擎盖正上方那一片:玻璃是斜的(rot -60),它的整体包围盒把它前上方
|
||
# 那几格也算了进去,但那里几乎全是空气,碰撞盒会悬在车外。
|
||
# 2) 引擎盖最前面(x=-3) 顶层(y=2):该层只有车头那 0.3 格高的一小条,比它后面一格
|
||
# (x=-2 顶层已被剔除) 高出来一截,看起来像引擎盖前端多出一块,一并剔除。
|
||
# 3) 警灯上方(x=-1) 顶层(y=3):驾驶室顶只有 2.79 高、警灯顶 3.02,这一层(3.0~3.5)全部
|
||
# 来自斜挡风玻璃包围盒的溢出,正好悬在警灯上方,看起来像警灯位置高出来一块。
|
||
SKIP_LOCAL = {
|
||
(-2, 2, -1), (-2, 2, 0), (-2, 2, 1),
|
||
(-2, 3, -1), (-2, 3, 0), (-2, 3, 1),
|
||
(-3, 2, -1), (-3, 2, 0), (-3, 2, 1),
|
||
(-1, 3, -1), (-1, 3, 0), (-1, 3, 1),
|
||
}
|
||
|
||
BLANK_MODEL = "dn_sa:ambulance_blank_model"
|
||
|
||
# 主方块碰撞盒模式(网易方块实体的模型可见性跟着「方块所在位置」走,主方块碰撞盒太小时,
|
||
# 玩家把屏幕转开、方块位置离开视野,整车的实体模型就会停止渲染而消失):
|
||
# "model":给主方块一个涵盖整车的碰撞盒(解决上述消失问题)
|
||
# "cell" :只用主方块自己那一格的碰撞盒(旧行为,其余碰撞靠占位方块)
|
||
MAIN_BOX_MODE = "model"
|
||
|
||
|
||
def model_box(bones, anchor):
|
||
"""整车在世界空间(相对主方块)的包围盒 (lo, hi)。"""
|
||
boxes = world_boxes(bones, False) # 含零厚度面片,才能真的涵盖整个模型
|
||
lo = [min(bx[0][i] for bx in boxes) + anchor[i] for i in range(3)]
|
||
hi = [max(bx[1][i] for bx in boxes) + anchor[i] for i in range(3)]
|
||
return lo, hi
|
||
|
||
|
||
def skip_cells(phi):
|
||
"""把车体局部格按 yaw 旋转成世界格(与几何体同向)。"""
|
||
out = set()
|
||
for (x, y, z) in SKIP_LOCAL:
|
||
if phi == 0:
|
||
ax, az = x, z
|
||
elif phi == 90:
|
||
ax, az = z, -x
|
||
elif phi == 180:
|
||
ax, az = -x, -z
|
||
else:
|
||
ax, az = -z, x
|
||
out.add((ax, y, az))
|
||
return out
|
||
|
||
|
||
# ---------------------------------------------------------------- math
|
||
def mat_mul(a, b):
|
||
return [[sum(a[i][k] * b[k][j] for k in range(3)) for j in range(3)] for i in range(3)]
|
||
|
||
|
||
def rot_axis(axis, deg):
|
||
t = math.radians(deg)
|
||
c, s = math.cos(t), math.sin(t)
|
||
if axis == 'x':
|
||
return [[1, 0, 0], [0, c, -s], [0, s, c]]
|
||
if axis == 'y':
|
||
return [[c, 0, s], [0, 1, 0], [-s, 0, c]]
|
||
return [[c, -s, 0], [s, c, 0], [0, 0, 1]]
|
||
|
||
|
||
def euler(rx, ry, rz):
|
||
m = rot_axis('y', ry)
|
||
m = mat_mul(m, rot_axis('x', rx))
|
||
m = mat_mul(m, rot_axis('z', rz))
|
||
return m
|
||
|
||
|
||
def apply(m, v, pivot):
|
||
d = [v[i] - pivot[i] for i in range(3)]
|
||
return [sum(m[i][k] * d[k] for k in range(3)) + pivot[i] for i in range(3)]
|
||
|
||
|
||
def cube_corners(cube):
|
||
o = cube['origin']
|
||
s = cube['size']
|
||
pt = cube.get('pivot', [0, 0, 0])
|
||
pts = [[o[0] + s[0] * dx, o[1] + s[1] * dy, o[2] + s[2] * dz]
|
||
for dx in (0, 1) for dy in (0, 1) for dz in (0, 1)]
|
||
rot = cube.get('rotation')
|
||
if rot and any(abs(v) > 1e-9 for v in rot):
|
||
m = euler(rot[0], rot[1], rot[2])
|
||
pts = [apply(m, p, pt) for p in pts]
|
||
return pts
|
||
|
||
|
||
def bone_world(by_name, bone, p):
|
||
b = bone
|
||
while b is not None:
|
||
rot = b.get('rotation')
|
||
if rot and any(abs(v) > 1e-9 for v in rot):
|
||
m = euler(rot[0], rot[1], rot[2])
|
||
p = apply(m, p, b.get('pivot', [0, 0, 0]))
|
||
b = by_name.get(b.get('parent'))
|
||
return p
|
||
|
||
|
||
def world_boxes(bones, skip_degenerate=True):
|
||
by_name = {b['name']: b for b in bones}
|
||
out = []
|
||
for b in bones:
|
||
for cube in b.get('cubes', []):
|
||
pts = [bone_world(by_name, b, p) for p in cube_corners(cube)]
|
||
# 网易方块实体:世界 X = -几何体 X(镜像),Y/Z 不变
|
||
pts = [[-p[0] / 16.0, p[1] / 16.0, p[2] / 16.0] for p in pts]
|
||
lo = [min(p[i] for p in pts) for i in range(3)]
|
||
hi = [max(p[i] for p in pts) for i in range(3)]
|
||
if skip_degenerate and (hi[0] - lo[0] < 1e-9 or hi[1] - lo[1] < 1e-9
|
||
or hi[2] - lo[2] < 1e-9):
|
||
continue # 零厚度面片不产生碰撞
|
||
out.append((lo, hi))
|
||
return out
|
||
|
||
|
||
def cells_for(boxes, anchor):
|
||
cells = {}
|
||
for lo, hi in boxes:
|
||
lo = [lo[i] + anchor[i] for i in range(3)]
|
||
hi = [hi[i] + anchor[i] for i in range(3)]
|
||
for ix in range(int(math.floor(lo[0])), int(math.floor(hi[0] - 1e-9)) + 1):
|
||
for iy in range(int(math.floor(lo[1])), int(math.floor(hi[1] - 1e-9)) + 1):
|
||
for iz in range(int(math.floor(lo[2])), int(math.floor(hi[2] - 1e-9)) + 1):
|
||
key = (ix, iy, iz)
|
||
l = [max(lo[0], ix), max(lo[1], iy), max(lo[2], iz)]
|
||
h = [min(hi[0], ix + 1), min(hi[1], iy + 1), min(hi[2], iz + 1)]
|
||
if key not in cells:
|
||
cells[key] = [l, h]
|
||
else:
|
||
pl, ph = cells[key]
|
||
cells[key] = [[min(pl[i], l[i]) for i in range(3)],
|
||
[max(ph[i], h[i]) for i in range(3)]]
|
||
return cells
|
||
|
||
|
||
def q(v, quant):
|
||
return round(v * quant) / float(quant)
|
||
|
||
|
||
def local_aabb(cell, l, h, quant=QUANT):
|
||
"""返回该格内 0~1 的局部 AABB(量化 1/quant),退化则返回 None。"""
|
||
lo = [min(1.0, max(0.0, q(l[i] - cell[i], quant))) for i in range(3)]
|
||
hi = [min(1.0, max(0.0, q(h[i] - cell[i], quant))) for i in range(3)]
|
||
if any(hi[i] - lo[i] <= 1e-6 for i in range(3)):
|
||
return None
|
||
return tuple(lo + hi)
|
||
|
||
|
||
# ---------------------------------------------------------------- per-car 计算
|
||
def load_model(path):
|
||
with io.open(path, 'r', encoding='utf-8') as f:
|
||
raw = json.load(f)
|
||
geo = raw['minecraft:geometry'][0]
|
||
root = [b['name'] for b in geo['bones'] if 'parent' not in b][0]
|
||
return geo, root
|
||
|
||
|
||
def bones_for_yaw(base_geo, root_name, phi):
|
||
"""车体世界旋转 φ 时对应的几何体骨骼:根骨骼 Y=90-φ,并把整车居中到主方块中心、车底贴地。"""
|
||
bones = json.loads(json.dumps(base_geo['bones']))
|
||
for b in bones:
|
||
if b['name'] == root_name:
|
||
r = list(b.get('rotation', [0, 0, 0]))
|
||
b['rotation'] = [r[0], r[1] - phi, r[2]]
|
||
# 求世界包围盒(已含 X 镜像,含零厚度面片),据此算居中/贴地平移量
|
||
boxes = world_boxes(bones, False)
|
||
lo = [min(bx[0][i] for bx in boxes) for i in range(3)]
|
||
hi = [max(bx[1][i] for bx in boxes) for i in range(3)]
|
||
cx = (lo[0] + hi[0]) / 2.0
|
||
cz = (lo[2] + hi[2]) / 2.0
|
||
tw = (0.5 - cx, -lo[1], 0.5 - cz) # 期望世界平移:X/Z 居中,车底 y=0
|
||
shift = [-16.0 * tw[0], 16.0 * tw[1], 16.0 * tw[2]] # 几何体空间平移 Δ = 16*diag(-1,1,1)*tw
|
||
for b in bones:
|
||
p = b.get('pivot', [0, 0, 0])
|
||
b['pivot'] = [p[i] + shift[i] for i in range(3)]
|
||
for c in b.get('cubes', []):
|
||
o = c['origin']
|
||
c['origin'] = [o[i] + shift[i] for i in range(3)]
|
||
if 'pivot' in c: # 立方体自带旋转轴心也需平移,否则非纯平移
|
||
cp = c['pivot']
|
||
c['pivot'] = [cp[i] + shift[i] for i in range(3)]
|
||
return bones
|
||
|
||
|
||
def wjson(path, obj):
|
||
with io.open(path, 'w', encoding='utf-8') as f:
|
||
f.write(json.dumps(obj, indent=2, ensure_ascii=False))
|
||
f.write(u"\n")
|
||
|
||
|
||
def block_json(identifier, aabb):
|
||
lo, hi = aabb
|
||
return {
|
||
"format_version": "1.10.0",
|
||
"minecraft:block": {
|
||
"description": {
|
||
"identifier": identifier,
|
||
"register_to_creative_menu": False,
|
||
"is_experimental": False,
|
||
"category": "dn_sa",
|
||
},
|
||
"components": {
|
||
"netease:solid": {"value": True},
|
||
"netease:render_layer": {"value": "alpha"},
|
||
"minecraft:destroy_time": {"value": 1.0},
|
||
"minecraft:block_light_absorption": {"value": 0},
|
||
"netease:aabb": {
|
||
"collision": {"min": list(lo), "max": list(hi)},
|
||
"clip": {"min": list(lo), "max": list(hi)},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
|
||
|
||
# 清理可能残留的旧文件(旧命名 / 旧的占位方块 / 旧的渲染锚点方块与客户端实体)
|
||
for f in os.listdir(BEH_BLOCKS_DIR):
|
||
if not f.endswith(".json"):
|
||
continue
|
||
if f == "ambulance_car_main.json" or ("ambulance_car" in f and "_ph_" in f):
|
||
os.remove(os.path.join(BEH_BLOCKS_DIR, f))
|
||
for f in os.listdir(ENTITY_DIR):
|
||
if not f.endswith(".json"):
|
||
continue
|
||
if "ambulance_car" in f and f.endswith("_block_entity.json"):
|
||
os.remove(os.path.join(ENTITY_DIR, f))
|
||
old_ent = os.path.join(ENTITY_DIR, "ambulance_car_main_block_entity.json")
|
||
if os.path.exists(old_ent):
|
||
os.remove(old_ent)
|
||
|
||
results = []
|
||
for car in CARS:
|
||
tag = car["tag"]
|
||
main_prefix = "dn_sa:%s_main" % tag
|
||
ph_prefix = "dn_sa:%s_ph_" % tag
|
||
geo_id = "geometry.dn_sa_%s" % tag
|
||
base_geo, root_name = load_model(car["src"])
|
||
|
||
per_yaw = {} # yaw -> {cell: local_aabb}(逐格碰撞盒)
|
||
yaw_bones = {} # yaw -> 已旋转/居中/贴地的骨骼
|
||
main_box = {} # yaw -> 整车包围盒(主方块「涵盖整个模型」碰撞盒)
|
||
shapes = {} # local_aabb -> None(形状共享)
|
||
for yaw in YAWS:
|
||
bones = bones_for_yaw(base_geo, root_name, yaw)
|
||
yaw_bones[yaw] = bones
|
||
cells = cells_for(world_boxes(bones), ANCHOR)
|
||
skip = skip_cells(yaw)
|
||
table = {}
|
||
removed = []
|
||
for cell, (l, h) in sorted(cells.items()):
|
||
if cell in skip:
|
||
removed.append(cell)
|
||
continue
|
||
la = local_aabb(cell, l, h)
|
||
if la is None:
|
||
continue
|
||
table[cell] = la
|
||
per_yaw[yaw] = table
|
||
main_box[yaw] = model_box(bones, ANCHOR)
|
||
for la in table.values():
|
||
shapes.setdefault(la, None)
|
||
print("[%s] yaw=%3d cells=%3d shapes=%3d removed=%s"
|
||
% (tag, yaw, len(table), len(set(table.values())), removed))
|
||
|
||
# 形状共享占位方块命名(每种「格内碰撞盒」一个变体,被多格复用)
|
||
names = {}
|
||
for i, shape in enumerate(sorted(shapes.keys())):
|
||
names[shape] = "%s%02d" % (ph_prefix, i)
|
||
# 每格最终方块名:主方块所在格用主方块,其余用形状共享占位方块
|
||
cellname = {}
|
||
for yaw in YAWS:
|
||
m = {}
|
||
for cell, la in per_yaw[yaw].items():
|
||
if cell == (0, 0, 0):
|
||
continue
|
||
m[cell] = names[la]
|
||
cellname[yaw] = m
|
||
print("[%s] placeholder shapes=%d" % (tag, len(names)))
|
||
|
||
# 1) 预旋转几何体:每个朝向一条,渲染整车
|
||
geos = []
|
||
for yaw in YAWS:
|
||
desc = dict(base_geo["description"])
|
||
desc["identifier"] = "%s_%d" % (geo_id, yaw)
|
||
geos.append({"description": desc, "bones": yaw_bones[yaw]})
|
||
wjson(os.path.join(MODELS_DIR, "%s_geo.json" % tag),
|
||
{"format_version": "1.21.0", "minecraft:geometry": geos})
|
||
|
||
# 2) client_entity:每个朝向一份,渲染整车
|
||
for yaw in YAWS:
|
||
name = "%s_%d" % (main_prefix, yaw)
|
||
ent = {
|
||
"format_version": "1.10.0",
|
||
"minecraft:client_entity": {
|
||
"description": {
|
||
"identifier": name,
|
||
"geometry": {"default": "%s_%d" % (geo_id, yaw)},
|
||
"textures": {"default": car["tex"]},
|
||
"materials": {"default": "entity_alphatest"},
|
||
"render_controllers": [
|
||
{"controller.render.dn_sa_ambulance_car_main": "variable.variant == 0"}
|
||
],
|
||
"scripts": {"initialize": ["variable.variant = 0;"]},
|
||
}
|
||
},
|
||
}
|
||
wjson(os.path.join(ENTITY_DIR, "%s_main_%d_block_entity.json" % (tag, yaw)), ent)
|
||
|
||
# 3) 方块定义:主方块(带 block_entity) + 形状共享占位方块
|
||
for yaw in YAWS:
|
||
name = "%s_%d" % (main_prefix, yaw)
|
||
if MAIN_BOX_MODE == "model":
|
||
lo, hi = main_box[yaw] # 一个碰撞盒涵盖整车
|
||
else:
|
||
la = per_yaw[yaw].get((0, 0, 0)) or (0.0, 0.0, 0.0, 1.0, 1.0, 1.0)
|
||
lo, hi = la[:3], la[3:]
|
||
obj = block_json(name, (lo, hi))
|
||
obj["minecraft:block"]["components"]["netease:block_entity"] = {"tick": False, "movable": False}
|
||
wjson(os.path.join(BEH_BLOCKS_DIR, "%s_main_%d.json" % (tag, yaw)), obj)
|
||
for shape, name in sorted(names.items(), key=lambda kv: kv[1]):
|
||
short = name.split(":", 1)[1]
|
||
wjson(os.path.join(BEH_BLOCKS_DIR, short + ".json"),
|
||
block_json(name, (shape[:3], shape[3:])))
|
||
|
||
results.append({
|
||
"item": car["item"], "tag": tag, "tex": car["tex"],
|
||
"main_prefix": main_prefix, "ph_prefix": ph_prefix,
|
||
"cellname": cellname, "names": names,
|
||
})
|
||
print("[%s] wrote geo + %d client_entity + %d block defs"
|
||
% (tag, len(YAWS), len(YAWS) + len(names)))
|
||
|
||
|
||
# ---------------------------------------------------------------- blocks.json
|
||
blocks = {"format_version": [1, 1, 0]}
|
||
blocks["dn_sa:generator"] = {
|
||
"sound": "stone",
|
||
"client_entity": {
|
||
"identifier": "dn_sa:generator",
|
||
"hand_model_use_client_entity": True,
|
||
"destroyed_textures": "dn_sa:generator_icon",
|
||
"block_icon": "dn_sa:generator_icon",
|
||
},
|
||
}
|
||
blocks["dn_sa:salvage_bin"] = {
|
||
"sound": "stone",
|
||
"client_entity": {
|
||
"identifier": "dn_sa:salvage_bin",
|
||
"hand_model_use_client_entity": True,
|
||
"destroyed_textures": "dn_sa:salvage_bin_icon",
|
||
"block_icon": "dn_sa:salvage_bin_icon",
|
||
},
|
||
}
|
||
for car in results:
|
||
for yaw in YAWS:
|
||
name = "%s_%d" % (car["main_prefix"], yaw)
|
||
blocks[name] = {
|
||
"sound": "stone",
|
||
"client_entity": {
|
||
"identifier": name,
|
||
"hand_model_use_client_entity": True,
|
||
"destroyed_textures": car["item"],
|
||
"block_icon": car["item"],
|
||
},
|
||
}
|
||
for car in results:
|
||
for shape, name in sorted(car["names"].items(), key=lambda kv: kv[1]):
|
||
blocks[name] = {"sound": "stone", "netease_model": BLANK_MODEL}
|
||
wjson(os.path.join(RP, "blocks.json"), blocks)
|
||
print("wrote blocks.json (%d entries)" % len(blocks))
|
||
|
||
|
||
# ---------------------------------------------------------------- terrain_texture.json
|
||
tt_path = os.path.join(RP, r"textures\terrain_texture.json")
|
||
with io.open(tt_path, 'r', encoding='utf-8') as f:
|
||
tt = json.load(f)
|
||
td = tt["texture_data"]
|
||
for legacy in ("dn_sa_ambulance_car_main", "dn_sa_ambulance_car_placeholder"):
|
||
td.pop(legacy, None)
|
||
for key in [k for k in td if k.startswith("dn_sa:ambulance") and "_ph_a" in k]:
|
||
td.pop(key, None) # 清掉上一次生成的渲染锚点贴图条目
|
||
for car in results:
|
||
td["dn_sa_%s" % car["tag"]] = {"textures": car["tex"]} # 方块破坏/图标贴图
|
||
for yaw in YAWS:
|
||
td["%s_%d" % (car["main_prefix"], yaw)] = {"textures": "textures/blocks/dn_sa_blank"}
|
||
wjson(tt_path, tt)
|
||
print("wrote terrain_texture.json")
|
||
|
||
|
||
# ---------------------------------------------------------------- 注入碰撞数据到 ambulanceServer.py
|
||
MARKER = u"# ==== AUTO-GENERATED LAYOUT DATA (by _gen_amb.py, do not edit) ===="
|
||
lines = []
|
||
lines.append(u"")
|
||
lines.append(MARKER)
|
||
lines.append(u"# 玩家朝向象限(0=南+Z,90=西-X,180=北-Z,270=东+X) -> 车体额外 Y 旋转角")
|
||
lines.append(u"EXTRA_BY_FACING = {")
|
||
for k in sorted(EXTRA_BY_FACING):
|
||
lines.append(u" %d: %d," % (k, EXTRA_BY_FACING[k]))
|
||
lines.append(u"}")
|
||
lines.append(u"# 物品名 -> 车型数据")
|
||
lines.append(u"CARS = {}")
|
||
for car in results:
|
||
lines.append(u"CARS['%s'] = {" % car["item"])
|
||
lines.append(u" 'main_prefix': '%s'," % car["main_prefix"])
|
||
lines.append(u" 'ph_prefix': '%s'," % car["ph_prefix"])
|
||
lines.append(u" 'main': {")
|
||
for yaw in YAWS:
|
||
lines.append(u" %d: '%s_%d'," % (yaw, car["main_prefix"], yaw))
|
||
lines.append(u" },")
|
||
lines.append(u" 'cells': {")
|
||
for yaw in YAWS:
|
||
lines.append(u" %d: {" % yaw)
|
||
for cell in sorted(car["cellname"][yaw].keys()):
|
||
if cell == (0, 0, 0):
|
||
continue
|
||
lines.append(u" (%d, %d, %d): '%s',"
|
||
% (cell[0], cell[1], cell[2], car["cellname"][yaw][cell]))
|
||
lines.append(u" },")
|
||
lines.append(u" },")
|
||
lines.append(u"}")
|
||
data_block = u"\n".join(lines)
|
||
|
||
server_path = os.path.join(BP, r"Script_dn_sa\ambulanceServer.py")
|
||
with io.open(server_path, 'r', encoding='utf-8') as f:
|
||
content = f.read()
|
||
idx = content.find(MARKER)
|
||
if idx < 0:
|
||
raise RuntimeError("marker not found in ambulanceServer.py")
|
||
with io.open(server_path, 'w', encoding='utf-8') as f:
|
||
f.write(content[:idx] + data_block + u"\n")
|
||
print("injected layout data into ambulanceServer.py")
|
||
|
||
old_layout = os.path.join(BP, r"Script_dn_sa\ambulanceLayout.py")
|
||
if os.path.exists(old_layout):
|
||
os.remove(old_layout)
|
||
print("DONE") |