# Desc: 将用到的关卡文件压缩成程序使用的protobuf格式 # Date: 2017-04-18 import os import sys import json import levelData_pb2 def read_json(file_path): with open(file_path, 'r') as file: return json.load(file) def write_json(data, file_path): with open(file_path, 'w+') as file: json.dump(data, file, indent=4) # 将 ../conf/levelInstInfo.csv 里面的每一个实例的模板名加上“tf_”前缀 def add_prefix_to_inst_name(): with open('../conf/levelInstInfo.csv', 'r') as f: hdr_done = False with open('../conf/levelInstInfo_new.csv', 'w+') as f_new: for line in f.readlines(): if line.startswith('#'): f_new.write(line) continue if not hdr_done: f_new.write(line) hdr_done = True continue line = line.split(',') if line[1].startswith('tf_'): f_new.write(line) continue line[1] = 'tf_' + line[1] f_new.write(','.join(line)) # 解析 ../conf/levelInstInfo.csv 文件,得到所有被用到的模板列表 def parse_level_inst_info(): temp_list = set() with open('../conf/levelInstInfo.csv', 'r') as f: # 跳过第一行 f.readline() for line in f.readlines(): if line.startswith('#'): continue temp_list.add(line.split(',')[1]) return temp_list # 将某个tiled的json文件转换成protobuf格式 def conver_json_to_proto(tDir, tFileName, outDir): global lvFileInfo, lvInfo jsonFile = os.path.join(tDir, tFileName + '.json') with open(jsonFile, 'r') as f:#, encoding='utf-8' jsonData = json.load(f) levelData = levelData_pb2.LevelData() levelData.tileWidth = jsonData['width'] levelData.tileHeight = jsonData['height'] cntUndefined = 0 tilesByPos = {} maxZ = 0 maxX = 0 maxY = 0 # 首先得到stacked的坐标数据 stacked_map = {} for item in jsonData['layers']: name = item['name'] if name == 'Marks': data = item['data'] for i in range(0, len(data)): if data[i] == 0: continue x = (int)(i % levelData.tileWidth) y = (int)(i / (int)(levelData.tileWidth)) stacked_map[(x, y)] = 0 # 处理各层的tile数据 for item in jsonData['layers']: name = item['name'] if not name.startswith('Tile_'): # stacked continue z = int(name[5:]) data = item['data'] for i in range(0, len(data)): if data[i] == 0: continue tile = levelData.tiles.add() tile.x = (int)(i % levelData.tileWidth) tile.y = (int)(i / (int)(levelData.tileWidth)) tile.z = z if (tile.x, tile.y) in stacked_map: stacked_map[(x, y)] += 1 tiledata = tile.tileData tiledata.zv = 0 tiledata.weight = 0 tiledata.id = data[i] if tiledata.id == -10: cntUndefined += 1 tiledata.type = 1 tiledata.subtype = 0 # 一些统计信息 tilesByPos[(tile.x, tile.y, tile.z)] = tile if tile.z > maxZ: maxZ = tile.z if tile.x > maxX: maxX = tile.x if tile.y > maxY: maxY = tile.y # 根据上面的布局信息,计算每个tile的几个信息: # 1. 每个tile的视觉层级(不同于上面z的信息,那是一个布局信息,相同的z可能出在不同的视觉层级) # 从maxZ开始,逐层向下计算;对于每一个位置,如果该位置有tile,则计算该tile的视觉层级 # 对于每一个tile,如果其上方(从该tile的z+1层,一直到maxZ层)有tile,则其视觉层级为上方tile的视觉层级+1 for z in range(0, maxZ+1): z = maxZ - z for x in range(0, maxX+1): for y in range(0, maxY+1): if (x,y,z) in tilesByPos: tile = tilesByPos[(x, y, z)] adjs = [(x,y),(x,y+1),(x,y-1),(x+1,y),(x+1,y+1),(x+1,y-1),(x-1,y),(x-1,y-1),(x-1,y+1)] # 确定视觉层级 zvMax = -1 for zup in range(z+1, maxZ+1): for adj in adjs: if (adj[0],adj[1],zup) in tilesByPos: zv = tilesByPos[adj[0],adj[1],zup].tileData.zv if zv > zvMax: zvMax = zv tile.tileData.zv = zvMax + 1 # 计算权重 # 从最底下开始,逐层向上计算 # 每个tile的初始权重为4,然后加上其下方压住的tile的权重:如果压了全部,则该加上被压住的tile权重; # 如果压住了一半,则加上被压住的tile权重的一半;如果是压住1/4,则加上被压住的tile权重的1/4 for z in range(0, maxZ+1): for x in range(0, maxX+1): for y in range(0, maxY+1): if (x,y,z) in tilesByPos: tile = tilesByPos[(x,y,z)] adjs = [(x,y,1.0),(x,y+1,0.5),(x,y-1,0.5),(x+1,y,0.5),(x+1,y+1,0.25),(x+1,y-1,0.25),(x-1,y,0.5),(x-1,y-1,0.25),(x-1,y+1,0.25)] weight = 4 for adj in adjs: # 从临近层往下,在某个位置找到了tile,则该tile被压住了,就不再找了 for zb in range(0, z): zb = z-1-zb if (adj[0], adj[1], zb) in tilesByPos: tileB = tilesByPos[(adj[0], adj[1], zb)] weight += tileB.tileData.weight * adj[2] break tile.tileData.weight = int(weight) pass for item in stacked_map: stack_data = levelData.stacks.add() stack_data.x = int(item[0]) stack_data.y = int(item[1]) stack_data.direction = 0 # 先默认都是0 # 数据序列化 level_protobuf_data = levelData.SerializeToString() protoFile = os.path.join(outDir, tFileName + '.bin') with open(protoFile, 'w+b') as f: f.write(level_protobuf_data) def gen_index_and_data(binDir, group = None): lvelsIndex = levelData_pb2.LevelsIndex() if group is not None: protoDataTrunk = os.path.join(binDir, 'levels-' + str(group) + '.bin') protoDataIndex = os.path.join(binDir, 'levelsIndex-' + str(group) + '.bin') else: protoDataTrunk = os.path.join(binDir, 'levels' + '.bin') protoDataIndex = os.path.join(binDir, 'levelsIndex' + '.bin') offset = 0 for filename in os.listdir(binDir): my_message = levelData_pb2.LevelData() binFile = os.path.splitext(filename)[0] + '.bin' binFile = os.path.join(binDir, binFile) if os.path.exists(binFile) : # print(binFile) with open(binFile, "rb") as f: binary_data = f.read() my_message.ParseFromString(binary_data) os.remove(binFile) with open(protoDataTrunk, 'ab') as f: f.write(binary_data) lvelsIndex.LevelsIndex[os.path.splitext(filename)[0]].len = len(binary_data) lvelsIndex.LevelsIndex[os.path.splitext(filename)[0]].offset = offset offset += len(binary_data) level_protobuf_index = lvelsIndex.SerializePartialToString() with open(protoDataIndex, 'w+b') as f: f.write(level_protobuf_index) # 将所有的模板文件转换成protobuf格式 def convert_all_templates(): temp_list = parse_level_inst_info() for temp_name in temp_list: print(f"Converting template {temp_name}") conver_json_to_proto('../tf_templates', temp_name, '../loadable') gen_index_and_data('../loadable') # 获取当前工作目录 current_dir = os.getcwd() script_dir = os.path.dirname(os.path.abspath(__file__)) os.chdir(script_dir) convert_all_templates() # 恢复当前工作目录 os.chdir(current_dir)