环境:cocos creator2.0.9;pyhon 3.7.4;PyCharm 2019.1.1 (Commuity Edition)。
接手别的同事的项目时,发现其中有个prefab有丢失脚本的情况(Missing Script),多达500多处,在项目内找寻了下,并没发现丢失脚本的uuid存在,说明这丢失的引用是无用的。一个一个去掉的话,太费时间,所以就用python处理下吧。btw,找寻脚本也是用python写的,下面就是:
#!/usr/bin/env python
# coding=utf-8
# PYTHON 3.7.4
import os
srcPath = '项目路径'
target = '64139e6e-740a-4807-8c20-66564751e25c' # 目标uuid
result = []
def findFilesByAppend():
print('findFilesByAppend target:{0}'.format(target))
for n, f, file in os.walk(srcPath):
if len(file) != 0:
for i in file:
if ".meta" in i: # 只找 .meta 文件
filetotledir = os.path.join(n, i)
print("读取filename:{0}".format(filetotledir))
with open(filetotledir) as file_object:
lines = file_object.readlines()
for line in lines:
if 'uuid' in line and target in line:
result.append(filetotledir)
else:
continue
if __name__ == "__main__":
findFilesByAppend()
print(result)
言归正传,首先,我们知道,在cocos creator中,prefab是个Json数组。而里面的节点是字典类型(具体可看https://blog.csdn.net/u013654125/article/details/87259315),我们要做的就是,遍历整个prefab,找出‘__type__’为丢失脚本的type的那些字典,然后删除。接着,我们还要找出引用这些丢失类的组件,组件结构如下:
我们需要做的就是,找到对应的id进行移除。(我用的是frame的'__id__')
以下是类结构:
移除完毕之后,放在引擎里编译,发现打不开,这是为什么呢?于是,我在引擎内手动去掉一个missingscript,通过svn比较之前版本发现,移除该类后,prefab内所有大于该类对应id的id,都会在自身基础上-1。
这就很好解决了,我们只需要递归遍历处理下,就可以了。下面是完整代码:
#!/usr/bin/env python
# coding=utf-8
# python 3.7.4
import time
import json
# 预制件批量去掉 无用的 类
srcPath = './sample/temp.prefab'
target_keyword = '641395udApIB4wgZlZHUeJc'
savePath = './sample/temp1.prefab'
tartget_list = []
components_list = [] # 丢失的组件的(creator 本身节点无__id__,通过frame的__id__来找)
# -------------------方法一 用json结构去处理(最佳方法) start-----------------------------
# {"__type__": "641395udApIB4wgZlZHUeJc", 丢失的类
# 递归 __id__ - 1
def findid(dict1, target_num):
if type(dict1) == dict:
for key_next_id, value_next_id in dict1.items():
if type(value_next_id) == dict:
if value_next_id.get('__id__'):
if value_next_id['__id__'] > target_num:
value_next_id['__id__'] = value_next_id['__id__'] - 1
else:
findid(value_next_id, target_num)
elif key_next_id == '__id__':
if dict1[key_next_id] > target_num:
dict1[key_next_id] = dict1[key_next_id] - 1
elif type(value_next_id) == list:
for list_item in value_next_id:
if type(list_item) == dict and list_item.get('__id__'):
if list_item['__id__'] > target_num:
list_item['__id__'] = list_item['__id__'] - 1
# else:
# print('其他 type:{2} key:{0},value:{1}'.format(key_next_id, value_next_id, type(value_next_id)))
else:
print('非字典类型')
def changePrefab():
file_in = open(srcPath, 'r', encoding='UTF-8') # 1,
file_out = open(savePath, 'w', encoding='UTF-8', newline='')
json_prefab = json.load(file_in)
# 找到丢失的目标类
for json_obj in json_prefab:
if json_obj['__type__'] == target_keyword:
tartget_list.append(json_obj)
# 倒序删才不会引起错误
tartget_list.sort(key=lambda ele: ele['frame']['__id__'], reverse=True)
print(tartget_list)
for tar in tartget_list:
# 删丢失的类
json_prefab.remove(tar)
# 删丢失的类在其他组件上的引用
for json_obj in json_prefab:
if json_obj['__type__'] == 'cc.Node':
for component in json_obj['_components']:
if tar['frame']['__id__'] == component['__id__']:
json_obj['_components'].remove(component)
break
# 递归 __id__ -1
for tar in tartget_list:
for json_obj in json_prefab:
findid(json_obj, tar['frame']['__id__'])
# indent=2按照缩进格式 ensure_ascii=False可以消除json包含中文的乱码问题
file_out.write(json.dumps(json_prefab, indent=2, ensure_ascii=False))
file_in.close()
file_out.close()
if __name__ == "__main__":
time1 = time.time()
print("-------------start---------------{0}".format(time1))
changePrefab()
time2 = time.time()
print("-------------end---------------{0}".format(time2))
print(u'总共耗时:' + str(time2 - time1) + 's')
到这,就达到我想要的效果了。
接下来,介绍下第二种方法,逐行读取,逐行写入。缺点是:较难通用,要算行数。有时会遇上坑,丢失的类结构有些参数为null,就会少算几行
import time
import json
def read_all_part(filename):
with open(filename, 'r', encoding='UTF-8', newline='') as f: # UTF-8 ASCII
lines = f.readlines()
return lines
# 预制件批量去掉 无用的 类
srcPath = './sample/temp.prefab'
target_keyword = '641395udApIB4wgZlZHUeJc'
savePath = './sample/temp1.prefab'
components_list = [] # 丢失的组件的(creator 本身节点无__id__,通过frame的__id__来找)
# 删除丢失的类
def delMissingClassType(target_str, key_words):
new_all_line = []
pop_list = []
is_value_null = {}
i = 0
for line in target_str:
if key_words in line:
pop_list.append(i)
if target_str[i + 10]:
if '"value": null' in target_str[i + 10]:
is_value_null[str(i)] = True
else: # 不是的话,就代表value是有值的
is_value_null[str(i)] = False
else:
print('无value或行数不对,i:', i)
new_all_line.append(line)
i = i + 1
# 删除要倒序删,不然索引会乱
pop_list.sort(reverse=True)
print('pop_list:', pop_list)
# 去除 那个类名的 用行数计算有坑,因为有时"value"是null 少2行
for pop_item in pop_list:
offest_num = 17
if is_value_null[str(pop_item)]:
offest_num = 15
j = pop_item + offest_num
while j > pop_item: # - 1
j = j - 1
new_all_line.pop(j)
return new_all_line
# 获取 丢失的类上对应的id
def get_id_list(target_str, key_words):
id_list = []
i = 0
for line in target_str:
if key_words in line:
if '__id__' in target_str[i + 8]:
key_id = target_str[i + 8].split(': ')
key_temp = key_id[1].split('\n')
new_num = int(key_temp[0], base=10)
id_list.append(new_num)
i = i + 1
print('id_list:', id_list)
return id_list
# 删除在组件列表上的丢失组件 (这部分出问题了,已修复)
def del_components_id(target_str, target_id_list):
new_all_line = []
id_line = []
i = 0
for line in target_str:
new_all_line.append(line)
for target_id in target_id_list:
if '"__id__": {0}\n'.format(str(target_id)) in line: # 加\n才可以
print('target_id:', target_id)
id_line.append(i)
break
i = i + 1
id_line.sort(reverse=True)
print('id_line', id_line)
for pop_item in id_line:
j = pop_item + 3
while j > pop_item:
j = j - 1
new_all_line.pop(j)
return new_all_line
# 序号排好
def need_to_write(target_str, target_num):
new_all_line = []
for line in target_str:
new_line_rep = line
if '__id__' in line:
key_id = line.split(': ')
key_temp = key_id[1].split('\n')
new_num = int(key_temp[0], base=10)
if new_num > target_num:
new_num = new_num - 1
new_line_rep = line.replace(key_temp[0], str(new_num))
new_all_line.append(new_line_rep)
return new_all_line
def othermain1():
all_str = read_all_part(srcPath)
# 删除 丢失的类的id: 641395udApIB4wgZlZHUeJc
new_all_line_temp = delMissingClassType(all_str, target_keyword)
# 获取 frame id
id_list = get_id_list(all_str, target_keyword)
# 删除components与该类上frame id相等的 __id__
new_all_line_temp1 = del_components_id(new_all_line_temp, id_list)
id_list.sort(reverse=True)
new_all_line2 = new_all_line_temp1
print(id_list)
for ids in id_list:
new_all_line = need_to_write(new_all_line2, ids)
new_all_line2 = new_all_line
# 是 __id__ -1
f = open(savePath, 'w', encoding='UTF-8', newline='') # windows 下cocos creator prefab的格式
f.writelines(new_all_line2)
f.close()
至此,就是我想要记录的内容了。如有错误,敬请各位大佬提点下,谢谢!