在unity资源中发现无效引用

本文主要解决在不打开unity的情况下搜索出无效引用的资源的方法

1. 概述

  1. 一般只要遍历一下目录里所有资源,判空一下就好了
  2. 但有些情况下,不希望打开unity, 尤其希望是在资源整合时,想更快验证资源的合法性, 这对合并提交及出包验证时,都要较大的需求

2. 简单的验证方法

  1. 简单来说,要直接分析untiy的资源文件, 而且unity资源大部分是文本文件
  2. 他们的文本格式大多是YAML, 如果直接使用PyYaml, 目前发现不行, 不过幸好, 格式相对简单, 通过分析属性的名称,再找到属性内容的方法,可以定位出Guid的值, 例如, 要查找XXX, YYY的值
import os

GuidStr = "guid: "
GuidStrLen = len(GuidStr)

class CheckAssetInfo:
    def __init__(self, filePath):
        self.filePath = filePath
        self.allGuids = []
        self.isInit = False
        self.checkValueNames = ["XXX", "YYY"]
        self.initData()

    def initData(self):
        if not self.isInit:
            self.allGuids = self.get_file_to_guids(self.filePath) 
            self.isInit = True

    def get_all_guids(self):
        return self.allGuids

    def get_target_value(self, valueName, valueInfos):
        for i in range(len(valueInfos)):
            n, j = valueInfos[i]
            if n == valueName:
                return i
        return -1

    def get_file_to_guids(self, targetFilterPath):
        allGuids = []
        with open(targetFilterPath, 'r') as assetFile:
            contentLines = assetFile.readlines()
            valueInfos = self.get_all_value_index(contentLines)
            for checkName in self.checkValueNames:
                valueIndex = self.get_target_value(checkName, valueInfos)
                if valueIndex != -1:
                    valueName, stline = valueInfos[valueIndex]
                    valueName, endLine = valueInfos[valueIndex+1]
                    allGuids.extend(self.get_value_guids(contentLines, stline, endLine))
        return allGuids

    def get_all_value_index(self, contentLines):
        valueInfos = []
        lineCount = len(contentLines)
        for i in range(lineCount):
            oneLine = contentLines[i]
            findIndex = oneLine.find(":")
            if findIndex != -1:
                valueName = oneLine[0:findIndex].strip()
                if valueName[0].isalpha():
                    valueInfos.append((valueName, i))
        valueInfos.append(("", lineCount))
        return valueInfos


    def get_value_guids(self, contentLines, startLineIndex, endLineIndex):
        allGuids = []

        for i in range(startLineIndex, endLineIndex):
            oneLine = contentLines[i]
            guidIndex = oneLine.find(GuidStr)
            if guidIndex != -1:
                endIndex = oneLine.find(", ", guidIndex)
                allGuids.append(oneLine[guidIndex + GuidStrLen: endIndex].strip())
        return allGuids
  1. 获得引用的GUID后,还要知道都有什么GUID的资源, 这个比较简单,只要分析meta文件就好, 以下就简单粗暴地遍历资源目录下的meta文件即可
class MetaInfo: 
    def __init__(self, filePath):
        self.filePath = filePath; 
        self.guid = self.get_guid_from_file(filePath)

    def get_guid_from_file(self, filePath):
        with open(filePath, 'r') as metaFile:
            allLine = metaFile.readlines()
            for oneLine in allLine:
                guidIndex = oneLine.find(GuidStr)
                if guidIndex != -1: 
                    return oneLine[guidIndex + GuidStrLen:len(oneLine)].strip()
        return ""
   
   class VegChecker: 
    def __init__(self, baseDir):
        self.checkAssetDir = "Assets/checkDir" 
        self.allAssetDir = "Assets"
        self.allAssetGuids = {}

    def get_all_target_files(self, targetDir, extName):
        res = []
        for root, dirs, files in os.walk(targetDir):
            for file in files:
                if os.path.splitext(file)[1] == extName:
                    file_path = os.path.join(root, file)
                    res.append(file_path)
        return res
    
    def get_all_asset_guids(self):
        allMetaFiles = self.get_all_veg_files(self.allAssetDir, ".meta")
        for metaFile in allMetaFiles:
            metaInfo = MetaInfo(metaFile)
            self.allAssetGuids[metaInfo.guid] = True
        print("Get total asset count meta count: " + str(len(self.allAssetGuids)))


  1. 获得要引用的GUID与所有的资源GUID,就很简单了,判断引用的GUID不在所有的资源GUID里就可以了
    def check_all_asset(self):
        res = True
        self.get_all_asset_guids()
        checkFiles = self.get_all_target_files(self.checkVegDir, ".asset")
        for oneFilter in checkFiles:
            assetInfo = CheckAssetInfo(oneFilter)
            for guid in assetInfo.allGuids:
                if not self.allAssetGuids.get(guid, False):
                    print(f"fail to find guid {guid} in check asset {oneFilter}")
                    res = False
        return res

3.Q&A

  1. 可能直接分析文件, 而且要大范围遍历文件,会有效率问题, 但实质试验下来, 还是挺快的, 测试验证几十个文件引用, 遍历了4万多个文件, 在i9机器,大概就8秒, 这已经比直接打开unity快多了.
  2. 当然会有分析错误的风险,但如果在一些相对明确的结构上, 也许是安全,但人工维护是免不了的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值