|
@@ -0,0 +1,213 @@
|
|
|
|
+# 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)
|