# 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(['','3']) 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') # 修改levelInstInfo.csv文件: 对于每一行,如果其try1一直到try10的随机数都是100,则一次将其加1 def correct_random_seed(): for f in ['../conf/levelInstInfo.csv', '../conf/levelInstInfo-2.csv']: lines = None with open(f, 'r') as file: lines = file.readlines() with open(f, 'w') as file: for line in lines: if line.startswith('#'): file.write(line) continue fs = line.split(',') if len(fs) < 12: file.write(line) continue for i in range(2, 12): if fs[i].split('|')[1] == '100': fs[i] = fs[i].replace('100', '%d' % (100+i)) file.write(','.join(fs)) # 将关卡实例每个关卡单独保存一个,避免改动的时候相互影响 def split_level_inst_info(): # 首先读取levelInfo.csv文件,对于每一个关卡,解析其所使用的实例名字信息 # 然后读取levelInstInfo.csv文件,得到每一个实例的详细信息 # 新建一个levelInstInfo-new.csv文件,对于每一个关卡,将其所使用的实例的信息改名成inst-关卡名,并存入上一步的详细信息 # 最后将levelInstInfo-new.csv文件保存 lvs_inst = {} with open('../conf/levelInfo-2.csv', 'r') as file: for line in file.readlines(): if line.startswith('#'): continue fs = line.split(',') lvs_inst[fs[0]] = (fs[1], fs) inst_info = {} with open('../conf/levelInstInfo-2.csv', 'r') as file: for line in file.readlines(): if line.startswith('#'): continue fs = line.split(',') inst_info[fs[0]] = ",".join(fs[1:]) # 更新info with open('../conf/levelInfo-2-new.csv', 'w') as file: for lv, (inst,li) in lvs_inst.items(): li[1] = 'inst-%s' % (lv,) file.write(",".join(li)) # 写入实例信息 with open('../conf/levelInstInfo-2-new.csv', 'w') as file: for lv, (inst,li) in lvs_inst.items(): if inst in inst_info: file.write("inst-%s,%s" % (lv, inst_info[inst])) else: print(f"Error: {inst} not found in levelInstInfo.csv") pass # 更新关卡实例的随机值 def updateRandomSeed(lvInfoFN, instInfoFN, seedsInfo): # seedsInfo每一行的格式:[Tile] resovler id: 31,37710|539110|14697|465925|662106|151463|667120|234313|60714|840794| # 解析seedsInfo,得到关卡和实例的时机值 seeds = {} for line in seedsInfo.split('\n'): fs = line.split(' ') if len(fs) < 4: continue fs = fs[3].split(',') seeds[fs[0]] = fs[1].split('|') # 先通过lvInfoFN文件,得到所有的关卡对应的实例名称 seeds4Inst = {} with open(lvInfoFN, 'r') as file: for line in file.readlines(): if line.startswith('#'): continue fs = line.split(',') if fs[0] in seeds: seeds4Inst[fs[1]] = seeds[fs[0]] # 对于instInfoFN文件,对于每一行,如果lvid在seeds里面,则用上面的随机值来更新一下;否则原封不动写入新文件 with open(instInfoFN, 'r') as infile: lines = infile.readlines() with open(instInfoFN + '-new', 'w') as outfile: for line in lines: fs = line.split(',') if len(fs) < 2: outfile.write(line) continue if fs[0] in seeds4Inst: for i in range(2, 12): v = seeds4Inst[fs[0]][i-2].split('-') ps = fs[i].split('|') ps[0] = v[0] ps[1] = v[1] fs[i] = '|'.join(ps) outfile.write(','.join(fs)) # 将instInfoFN-new文件重命名为instInfoFN os.rename(instInfoFN + '-new', instInfoFN) pass if __name__ == '__main__': # 获取当前工作目录 current_dir = os.getcwd() script_dir = os.path.dirname(os.path.abspath(__file__)) os.chdir(script_dir) # 得到可以发布的protobuf文件 # convert_all_templates() # correct_random_seed() # split_level_inst_info() # 更新随机信息 seedsInfo = """ [Tile] resovler id: 25,7-341610|6-262325|6-945921|6-473668|6-128340|6-2892|6-72626|6-893012|6-408548|6-44503| [Tile] resovler id: 26,7-567613|6-379105|6-850011|7-290409|6-519083|6-432876|6-942100|6-274091|6-237419|6-179412| [Tile] resovler id: 27,9-377089|8-919618|7-859942|7-699142|7-418060|7-687768|7-854285|7-570664|7-72134|7-247144| [Tile] resovler id: 28,7-488088|5-265529|6-788870|6-979469|6-818177|6-983170|6-144435|6-350100|6-954211|6-980536| [Tile] resovler id: 29,9-15846|8-871897|8-311662|8-293447|7-804047|7-885158|7-414106|7-31288|7-327241|7-979414| [Tile] resovler id: 30,9-872816|9-200069|8-314634|8-477935|8-743749|8-597368|8-983810|8-193666|7-487585|7-722035| [Tile] resovler id: 31,9-998180|9-299273|8-949613|8-412564|8-444406|8-553034|8-116508|8-5708|8-566134|8-699614| [Tile] resovler id: 32,9-763414|9-988866|8-553506|8-253789|7-741396|7-500411|7-805018|7-389569|7-845276|7-313335| [Tile] resovler id: 33,8-102828|6-216194|7-114590|7-259842|7-559078|7-893772|7-728323|7-13890|7-255809|7-280572| [Tile] resovler id: 34,9-90440|9-401323|8-516911|8-248769|8-776515|8-746085|8-397365|8-37564|8-541355|8-255120| [Tile] resovler id: 35,11-247285|10-810932|10-100934|9-102272|9-944882|9-204255|9-555059|9-52477|9-916439|9-946541| [Tile] resovler id: 36,9-363314|9-247562|8-973740|8-307516|8-881629|8-333555|8-511025|8-825751|8-763137|8-345186| [Tile] resovler id: 37,6-370229|6-239105|6-445902|6-920948|6-660307|7-248341|7-265246|6-96751|7-228173|7-423060| [Tile] resovler id: 38,8-642127|8-44859|7-504201|7-31700|7-499255|7-698402|7-153744|7-860229|7-742799|7-811031| [Tile] resovler id: 39,9-913284|9-951378|8-382312|8-437694|8-279055|8-424757|8-639322|8-576705|8-485431|8-430052| [Tile] resovler id: 40,7-696477|7-33900|8-119957|7-940172|7-99802|7-792344|7-655357|8-207736|8-455232|8-684503| [Tile] resovler id: 41,10-788132|10-742310|10-868868|9-138244|9-794303|9-385431|9-253451|8-908781|8-150327|8-938588| [Tile] resovler id: 42,12-732881|12-547653|11-813343|11-836719|10-938074|10-931711|10-644864|10-863521|10-415599|10-77497| [Tile] resovler id: 43,10-610224|10-973379|9-163942|9-481277|9-644467|9-350239|9-616049|9-366997|9-97698|9-635651| [Tile] resovler id: 44,14-52787|14-528276|13-909860|13-16181|13-236545|12-8570|12-722536|12-296225|12-158053|12-966578| [Tile] resovler id: 45,11-243810|12-96805|11-54683|12-438169|11-338719|10-530372|10-900325|10-900451|10-630413|10-570106| [Tile] resovler id: 46,8-791094|9-371251|9-676014|9-19207|8-935075|8-178931|8-916878|8-658910|8-216667|8-257354| [Tile] resovler id: 47,10-505382|9-499194|10-828522|9-816513|9-775689|9-597962|9-550814|9-95365|9-709569|9-552908| [Tile] resovler id: 48,7-120090|9-575552|8-315110|8-554649|8-463145|3-401102|3-204291|3-451939|4-220184|3-641713| [Tile] resovler id: 49,5-528105|4-885959|5-899692|5-602010|4-545985|5-596026|5-136995|5-698681|5-252227|5-47798| [Tile] resovler id: 50,12-635284|12-400697|11-52445|10-408269|10-657076|10-440321|10-89234|10-165772|10-425500|9-351002| [Tile] resovler id: 51,15-171695|13-68697|12-601255|12-736632|12-590389|12-255975|12-337435|12-621772|12-276310|12-995441| [Tile] resovler id: 52,14-608516|10-203251|8-788333|14-736941|12-672215|10-223334|12-820599|12-270827|10-355041|10-24539| [Tile] resovler id: 53,13-673433|11-327072|11-761830|16-217035|13-174556|13-300604|13-29917|13-639017|13-558354|13-309239| [Tile] resovler id: 54,17-40211|12-872976|12-703087|16-683902|16-111094|17-655813|14-554089|16-100388|16-531335|16-834959| [Tile] resovler id: 55,14-375711|9-118026|7-272489|10-434034|12-143509|10-6859|9-44251|9-437285|10-812657|10-29062| [Tile] resovler id: 56,16-34443|14-807113|9-686602|14-501291|12-216059|16-592701|16-4976|16-513291|14-892878|14-455292| [Tile] resovler id: 57,18-673682|15-720807|13-674941|18-510748|17-408080|17-525548|17-261853|17-329768|18-658693|18-175945| [Tile] resovler id: 58,14-720029|12-406840|10-645269|15-81879|13-388640|13-542548|14-943324|13-6752|12-364355|12-473514| [Tile] resovler id: 59,12-180286|9-902545|7-897819|12-811614|11-924670|11-185724|11-48430|9-610620|9-973340|9-388493| [Tile] resovler id: 60,16-378214|12-819875|11-463132|16-794525|16-945954|16-425471|16-771707|14-203910|12-225743|12-281303| [Tile] resovler id: 61,17-182597|16-184736|14-717220|17-860539|17-214411|17-113674|17-518804|16-473156|16-274588|16-742004| [Tile] resovler id: 62,16-611|14-200559|10-164706|17-93461|17-684187|16-11041|14-155328|14-635091|12-664863|12-598720| [Tile] resovler id: 63,16-933468|14-669665|12-279363|16-391703|14-588361|14-289149|14-494528|16-599309|15-210394|16-682849| [Tile] resovler id: 64,16-216364|14-768792|12-308913|17-768426|17-738253|17-614829|16-722577|14-657197|14-139891|14-448502| [Tile] resovler id: 65,10-39852|9-559626|6-76214|10-718926|9-338797|9-33080|9-683259|8-561606|8-426209|8-85242| [Tile] resovler id: 66,16-899743|14-423102|9-31749|16-974369|14-105893|16-954567|12-929064|14-287147|12-257060|12-623200| [Tile] resovler id: 67,17-304729|16-384210|12-257625|17-314353|17-893772|18-606129|18-297148|17-131673|14-784002|14-190726| [Tile] resovler id: 68,17-410681|15-768967|11-81391|17-340026|17-197497|17-775247|17-901047|15-665976|15-502478|15-914611| [Tile] resovler id: 69,12-321284|12-739422|8-484006|15-896910|14-677777|15-450233|10-52907|12-428201|10-441209|10-823854| [Tile] resovler id: 70,18-572065|13-990765|11-880379|18-536300|16-948853|16-615238|15-421155|15-454710|13-443886|13-701271| [Tile] resovler id: 71,13-481253|11-756402|11-770766|16-57272|14-863255|12-529289|13-214231|13-583642|13-656662|11-974420| [Tile] resovler id: 72,12-813001|12-594052|9-349991|12-230482|10-492191|12-446794|11-30687|12-325640|9-823522|9-136551| [Tile] resovler id: 73,16-457055|12-47994|10-557232|14-949057|15-97802|14-619333|12-198322|12-802861|12-601970|12-376792| [Tile] resovler id: 74,14-117315|14-540591|12-588370|14-213629|14-757870|14-85482|14-366335|14-511209|12-933919|12-493089| [Tile] resovler id: 75,17-797637|13-861573|11-100042|17-510654|16-1835|17-219010|16-369236|16-568965|13-252172|13-833809| [Tile] resovler id: 76,18-794231|15-827668|18-942110|18-404360|18-422771|18-624509|18-329176|16-440697|18-535528|18-917276| [Tile] resovler id: 77,18-354081|16-344623|14-532930|18-540815|17-23786|18-929712|17-743020|16-999279|17-995555|17-172066| [Tile] resovler id: 78,17-580555|14-904064|12-326822|17-616516|16-601490|16-934590|17-689133|16-138293|14-412350|14-412923| [Tile] resovler id: 79,11-361860|7-353099|7-725424|11-364145|11-138344|9-793923|9-528013|9-873439|9-667265|9-878410| [Tile] resovler id: 80,10-31033|7-329259|10-447049|10-926203|9-991517|10-162175|9-233838|9-842085|9-772360|9-839139| [Tile] resovler id: 81,18-87609|14-315533|19-925752|17-763456|16-355542|17-832654|18-409050|16-522776|14-624601|17-995036| [Tile] resovler id: 82,18-878683|12-903771|18-988848|18-781041|16-914398|16-74199|16-960252|15-733529|15-125376|16-920581| [Tile] resovler id: 83,19-73678|13-414863|19-647222|17-697643|17-972345|16-890752|17-853482|17-965095|16-521942|15-562364| [Tile] resovler id: 84,19-815835|15-14671|17-894705|19-774467|19-850870|16-140801|17-657994|17-900680|19-880891|16-761085| [Tile] resovler id: 85,15-192686|11-334787|9-118658|15-247606|13-350360|11-922803|13-684873|13-33550|9-154659|9-675174| [Tile] resovler id: 86,12-541386|10-967203|11-901006|11-856068|11-370551|11-843500|12-928773|11-153754|11-996884|10-413325| [Tile] resovler id: 87,16-787581|11-847118|18-118893|13-659698|16-253226|15-894559|16-812321|16-1497|15-847956|11-773433| [Tile] resovler id: 88,13-1956|9-143439|14-644282|14-988156|12-784450|12-570588|14-495741|10-690821|10-717969|9-232747| [Tile] resovler id: 89,13-669016|10-14320|8-68756|13-591339|12-204669|10-790926|10-294117|12-403642|10-460469|10-378875| [Tile] resovler id: 90,19-816676|15-35394|19-317226|19-7014|16-937968|17-927872|19-671907|17-310498|15-76566|14-653328| [Tile] resovler id: 91,16-468177|13-61558|15-671487|17-550117|16-192925|17-477865|16-473309|19-915730|17-486703|15-576887| [Tile] resovler id: 92,11-67296|7-696457|13-116512|12-381071|12-729161|12-632052|14-958939|10-331801|9-483227|10-891943| [Tile] resovler id: 93,17-888209|14-104480|17-450375|16-349736|17-68965|16-9702|16-327059|15-510881|14-106281|14-153663| [Tile] resovler id: 94,14-531553|8-496919|12-540410|12-270084|10-688059|10-457035|12-684333|10-943615|10-635612|8-207819| [Tile] resovler id: 95,17-106979|17-72415|12-46023|17-636604|17-493080|17-659368|17-150214|17-852232|15-932584|15-51251| [Tile] resovler id: 96,18-869352|13-944228|16-514449|16-812866|16-473186|15-350504|15-82949|13-200680|13-379246|15-863221| [Tile] resovler id: 97,18-81387|12-306675|16-741517|16-812747|15-199378|16-857759|14-324036|12-371416|12-292829|13-630633| [Tile] resovler id: 98,14-517142|14-708568|12-659801|12-657691|10-548711|12-790244|12-446895|13-62844|13-353753|13-692671| [Tile] resovler id: 99,17-785205|15-958578|11-72177|15-881422|17-298547|17-627995|17-2147|17-357842|13-208586|13-607505| [Tile] resovler id: 100,18-946430|13-982527|17-321736|18-249529|16-241206|18-54762|15-386411|17-109401|17-419348|16-510358| """ updateRandomSeed('../conf/levelInfo-3.csv', '../conf/levelInstInfo-3.csv', seedsInfo) # 恢复当前工作目录 os.chdir(current_dir)