123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- # 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(groups):
- temp_list = set()
- for grp in groups:
- fn = '../conf/levelInstInfo.csv'
- if len(grp) != 0:
- fn = '../conf/levelInstInfo-' + grp + '.csv'
- with open(fn, '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数据
- cntTiles = 0
- 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
- cntTiles += 1
- if cntTiles%3 != 0:
- print('Error: tile count is not a multiple of 3: %d' % (cntTiles,))
- exit(1)
- # 根据上面的布局信息,计算每个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():
- # 清空loadable目录
- for root, dirs, files in os.walk('../loadable'):
- for name in files:
- os.remove(os.path.join(root, name))
- temp_list = parse_level_inst_info(['','2'])
- dirs = ['../tf_templates', '../miniGame', '../templates']
- for temp_name in temp_list:
- print(f"Converting template {temp_name}")
- # 判断正确的目录
- for d in dirs:
- if os.path.exists(os.path.join(d, temp_name + '.json')):
- conver_json_to_proto(d, temp_name, '../loadable')
- break
- 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)
|