python 批量清除coco creator prefab上特定的Missing Script

        环境: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()

至此,就是我想要记录的内容了。如有错误,敬请各位大佬提点下,谢谢!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值