conv_lvs.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. # Desc: 将用到的关卡文件压缩成程序使用的protobuf格式
  2. # Date: 2017-04-18
  3. import os
  4. import sys
  5. import json
  6. import levelData_pb2
  7. def read_json(file_path):
  8. with open(file_path, 'r') as file:
  9. return json.load(file)
  10. def write_json(data, file_path):
  11. with open(file_path, 'w+') as file:
  12. json.dump(data, file, indent=4)
  13. # 将 ../conf/levelInstInfo.csv 里面的每一个实例的模板名加上“tf_”前缀
  14. def add_prefix_to_inst_name():
  15. with open('../conf/levelInstInfo.csv', 'r') as f:
  16. hdr_done = False
  17. with open('../conf/levelInstInfo_new.csv', 'w+') as f_new:
  18. for line in f.readlines():
  19. if line.startswith('#'):
  20. f_new.write(line)
  21. continue
  22. if not hdr_done:
  23. f_new.write(line)
  24. hdr_done = True
  25. continue
  26. line = line.split(',')
  27. if line[1].startswith('tf_'):
  28. f_new.write(line)
  29. continue
  30. line[1] = 'tf_' + line[1]
  31. f_new.write(','.join(line))
  32. # 解析 ../conf/levelInstInfo.csv 文件,得到所有被用到的模板列表
  33. def parse_level_inst_info():
  34. temp_list = set()
  35. with open('../conf/levelInstInfo.csv', 'r') as f:
  36. # 跳过第一行
  37. f.readline()
  38. for line in f.readlines():
  39. if line.startswith('#'):
  40. continue
  41. temp_list.add(line.split(',')[1])
  42. return temp_list
  43. # 将某个tiled的json文件转换成protobuf格式
  44. def conver_json_to_proto(tDir, tFileName, outDir):
  45. global lvFileInfo, lvInfo
  46. jsonFile = os.path.join(tDir, tFileName + '.json')
  47. with open(jsonFile, 'r') as f:#, encoding='utf-8'
  48. jsonData = json.load(f)
  49. levelData = levelData_pb2.LevelData()
  50. levelData.tileWidth = jsonData['width']
  51. levelData.tileHeight = jsonData['height']
  52. cntUndefined = 0
  53. tilesByPos = {}
  54. maxZ = 0
  55. maxX = 0
  56. maxY = 0
  57. # 首先得到stacked的坐标数据
  58. stacked_map = {}
  59. for item in jsonData['layers']:
  60. name = item['name']
  61. if name == 'Marks':
  62. data = item['data']
  63. for i in range(0, len(data)):
  64. if data[i] == 0:
  65. continue
  66. x = (int)(i % levelData.tileWidth)
  67. y = (int)(i / (int)(levelData.tileWidth))
  68. stacked_map[(x, y)] = 0
  69. # 处理各层的tile数据
  70. for item in jsonData['layers']:
  71. name = item['name']
  72. if not name.startswith('Tile_'):
  73. # stacked
  74. continue
  75. z = int(name[5:])
  76. data = item['data']
  77. for i in range(0, len(data)):
  78. if data[i] == 0:
  79. continue
  80. tile = levelData.tiles.add()
  81. tile.x = (int)(i % levelData.tileWidth)
  82. tile.y = (int)(i / (int)(levelData.tileWidth))
  83. tile.z = z
  84. if (tile.x, tile.y) in stacked_map:
  85. stacked_map[(x, y)] += 1
  86. tiledata = tile.tileData
  87. tiledata.zv = 0
  88. tiledata.weight = 0
  89. tiledata.id = data[i]
  90. if tiledata.id == -10:
  91. cntUndefined += 1
  92. tiledata.type = 1
  93. tiledata.subtype = 0
  94. # 一些统计信息
  95. tilesByPos[(tile.x, tile.y, tile.z)] = tile
  96. if tile.z > maxZ:
  97. maxZ = tile.z
  98. if tile.x > maxX:
  99. maxX = tile.x
  100. if tile.y > maxY:
  101. maxY = tile.y
  102. # 根据上面的布局信息,计算每个tile的几个信息:
  103. # 1. 每个tile的视觉层级(不同于上面z的信息,那是一个布局信息,相同的z可能出在不同的视觉层级)
  104. # 从maxZ开始,逐层向下计算;对于每一个位置,如果该位置有tile,则计算该tile的视觉层级
  105. # 对于每一个tile,如果其上方(从该tile的z+1层,一直到maxZ层)有tile,则其视觉层级为上方tile的视觉层级+1
  106. for z in range(0, maxZ+1):
  107. z = maxZ - z
  108. for x in range(0, maxX+1):
  109. for y in range(0, maxY+1):
  110. if (x,y,z) in tilesByPos:
  111. tile = tilesByPos[(x, y, z)]
  112. 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)]
  113. # 确定视觉层级
  114. zvMax = -1
  115. for zup in range(z+1, maxZ+1):
  116. for adj in adjs:
  117. if (adj[0],adj[1],zup) in tilesByPos:
  118. zv = tilesByPos[adj[0],adj[1],zup].tileData.zv
  119. if zv > zvMax:
  120. zvMax = zv
  121. tile.tileData.zv = zvMax + 1
  122. # 计算权重
  123. # 从最底下开始,逐层向上计算
  124. # 每个tile的初始权重为4,然后加上其下方压住的tile的权重:如果压了全部,则该加上被压住的tile权重;
  125. # 如果压住了一半,则加上被压住的tile权重的一半;如果是压住1/4,则加上被压住的tile权重的1/4
  126. for z in range(0, maxZ+1):
  127. for x in range(0, maxX+1):
  128. for y in range(0, maxY+1):
  129. if (x,y,z) in tilesByPos:
  130. tile = tilesByPos[(x,y,z)]
  131. 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)]
  132. weight = 4
  133. for adj in adjs:
  134. # 从临近层往下,在某个位置找到了tile,则该tile被压住了,就不再找了
  135. for zb in range(0, z):
  136. zb = z-1-zb
  137. if (adj[0], adj[1], zb) in tilesByPos:
  138. tileB = tilesByPos[(adj[0], adj[1], zb)]
  139. weight += tileB.tileData.weight * adj[2]
  140. break
  141. tile.tileData.weight = int(weight)
  142. pass
  143. for item in stacked_map:
  144. stack_data = levelData.stacks.add()
  145. stack_data.x = int(item[0])
  146. stack_data.y = int(item[1])
  147. stack_data.direction = 0 # 先默认都是0
  148. # 数据序列化
  149. level_protobuf_data = levelData.SerializeToString()
  150. protoFile = os.path.join(outDir, tFileName + '.bin')
  151. with open(protoFile, 'w+b') as f:
  152. f.write(level_protobuf_data)
  153. def gen_index_and_data(binDir, group = None):
  154. lvelsIndex = levelData_pb2.LevelsIndex()
  155. if group is not None:
  156. protoDataTrunk = os.path.join(binDir, 'levels-' + str(group) + '.bin')
  157. protoDataIndex = os.path.join(binDir, 'levelsIndex-' + str(group) + '.bin')
  158. else:
  159. protoDataTrunk = os.path.join(binDir, 'levels' + '.bin')
  160. protoDataIndex = os.path.join(binDir, 'levelsIndex' + '.bin')
  161. offset = 0
  162. for filename in os.listdir(binDir):
  163. my_message = levelData_pb2.LevelData()
  164. binFile = os.path.splitext(filename)[0] + '.bin'
  165. binFile = os.path.join(binDir, binFile)
  166. if os.path.exists(binFile) :
  167. # print(binFile)
  168. with open(binFile, "rb") as f:
  169. binary_data = f.read()
  170. my_message.ParseFromString(binary_data)
  171. os.remove(binFile)
  172. with open(protoDataTrunk, 'ab') as f:
  173. f.write(binary_data)
  174. lvelsIndex.LevelsIndex[os.path.splitext(filename)[0]].len = len(binary_data)
  175. lvelsIndex.LevelsIndex[os.path.splitext(filename)[0]].offset = offset
  176. offset += len(binary_data)
  177. level_protobuf_index = lvelsIndex.SerializePartialToString()
  178. with open(protoDataIndex, 'w+b') as f:
  179. f.write(level_protobuf_index)
  180. # 将所有的模板文件转换成protobuf格式
  181. def convert_all_templates():
  182. temp_list = parse_level_inst_info()
  183. for temp_name in temp_list:
  184. print(f"Converting template {temp_name}")
  185. conver_json_to_proto('../tf_templates', temp_name, '../loadable')
  186. gen_index_and_data('../loadable')
  187. # 获取当前工作目录
  188. current_dir = os.getcwd()
  189. script_dir = os.path.dirname(os.path.abspath(__file__))
  190. os.chdir(script_dir)
  191. convert_all_templates()
  192. # 恢复当前工作目录
  193. os.chdir(current_dir)