Cocos2dx的cache细节,资源路径不规范,容易导致cache中存在多份

简介: Cocos2dx的cache细节,资源路径不规范,容易导致cache中存在多份

SpriteFrameCache

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("");
复制代码

TextureCache

std::unordered_map<std::string, TexInfo*> _textures;
复制代码

key的来源

Texture2D * TextureCache::addImage(const std::string &path){
    std::string fullpath = GetFullPath(path);
    auto it = _textures.find(fullpath);
}
std::string GetFullPath(std::string path){
    std::string fullPath = FileUtils::getInstance()->fullPathForFilename(path);
    if (fullPath.length() > 0){
        return fullPath;
    }else{
        return path;
    }
}
std::string FileUtils::fullPathForFilename(const std::string &filename) const
{
    if (path[0] == '/')
    {
        return filename;
    }
    std::string name = filename;
    int index = name.find("/../");
    while (index > 0) {
            int last = name.find_last_of("/", index-1);
            if (last > 0) {
                    name = name.substr(0, last) + name.substr(index+3, name.length());
            }
            else {
                    break;
            }
            index = name.find("/../");
    }
    // Already Cached ?
    auto cacheIter = _fullPathCache.find(name);
    // 又一个很重要的cache: mutable std::unordered_map<std::string, std::string> _fullPathCache;
    if(cacheIter != _fullPathCache.end())
    {
        return cacheIter->second;
    }
    // Get the new file name.
    const std::string newFilename(getNewFilename(name));
    std::string fullpath;
    for (const auto& searchIt : _searchPathArray){
        for (const auto& resolutionIt : _searchResolutionsOrderArray){
            fullpath = this->getPathForFilename(newFilename, resolutionIt, searchIt);
            if (!fullpath.empty()){
                // Using the filename passed in as key.
                _fullPathCache.emplace(name, fullpath);
                return fullpath;
            }
        }
    }
    return "";
}
复制代码

测试结果

网络异常,图片无法展示
|

  • name为ani1/test.png,在textureCache中的映射key为res/ani1/test.png
  • name为res/ani1/test.png,在textureCache中的映射key为exePath/res/ani1/test.png

相当于加载的是磁盘的同一份图片,结果却产生了2个纹理,理想情况是产生1份,产生这个问题的原因是:

TextureCache的key受filePathCache的影响,而filePathCache受searchPath的影响

searchPath的目录的顺序为:

  • exePath
  • src
  • res

ani1/test.png只能在res目录下找到,res/ani1/test.png只能在exePath目录下找到,所以最终2者的key是完全不同的。

造成这个问题是因为我设置了一个无效的searchPath,而在win32平台判断文件是否存在发生了异常

bool FileUtilsWin32::isFileExistInternal(const std::string& strFilePath) const
{
    if (strFilePath.empty())
    {
        return false;
    }
    std::string strPath = strFilePath;
    if (!isAbsolutePath(strPath))
    { // Not absolute path, add the default root path at the beginning.
        strPath.insert(0, _defaultResRootPath);
    }
    DWORD attr = GetFileAttributesW(StringUtf8ToWideChar(strPath).c_str());
    if(attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY))
        return false;   //  not a file
    return true;
}
复制代码

当strFile为res/ani1/test.png返回的是FILE_ATTRIBUTE_ARCHIVEisFileExistInternal直接返回了true,认为存在,准确说这个文件是相对于exe是存在的,但是这个路径不是完整路径

  • 测试代码:
char* file = "res/ani2/test.png"; // exe运行目录下真的有这个文件
//file = "c://a/1.png";
DWORD attr = GetFileAttributesW(StringUtf8ToWideChar(file).c_str());
if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY))
{
    cocos2d::log("file not exist");
}
else{
    cocos2d::log("file exist");
}
复制代码

为什么会出现search paths异常

FileUtils::getInstance()->addSearchPath("res");
void FileUtils::addSearchPath(const std::string &searchpath,const bool front)
{
    if (!isAbsolutePath(searchpath))
        prefix = _defaultResRootPath;
}
复制代码

当添加searchPaths的时候,如果是相对路径,则会追加_defaultResRootPath,而_defaultResRootPath在win32上的来源是ProjectConfig,在SimulatorWin::run中就会从命令行参数中解析workdir最终传递给_defaultResRootPath

void FileUtils::setDefaultResourceRootPath(const std::string& path)
{
    // 最主要的原因是这里缺少对path的校验
    if (_defaultResRootPath != path)
    {
        _fullPathCache.clear();
        _defaultResRootPath = path;
        if (!_defaultResRootPath.empty() && _defaultResRootPath[_defaultResRootPath.length()-1] != '/')
        {
            _defaultResRootPath += '/';
        }
        // Updates search paths
        setSearchPaths(_originalSearchPaths);
    }
}
复制代码

release出现问题就是因为args中缺少workdir

网络异常,图片无法展示
|
原始的win32项目填写了Command Arguments,所以规避了这个问题

结论

SearchPath的影响还是非常大的,写资源路径的时候,最好统一相对于一个目录写,不然cache中容易出现多份相同的资源。



目录
相关文章
|
缓存 前端开发 JavaScript
如何优化Yii2视图文件的加载速度?具体步骤是怎样的?底层原理是什么?
如何优化Yii2视图文件的加载速度?具体步骤是怎样的?底层原理是什么?
160 0
|
文件存储
Yii2.0框架提供了内置的文件访问组件,可以通过配置只允许访问指定的目录,防止非法文件的包含。这个如何使用?
Yii2.0框架提供了内置的文件访问组件,可以通过配置只允许访问指定的目录,防止非法文件的包含。这个如何使用?
152 0
|
JavaScript
js如何拷贝元数据后,更改数据不对元数据有影响
js如何拷贝元数据后,更改数据不对元数据有影响
|
XML 缓存 NoSQL
分布式服务器框架之Server.Common中通过Xml配置渠道、服务器集群、热更新信息代码解析Xml缓存进内存
ChannelConfig.cs代码解析加载ChannelConfig.xml。使用了System.Xml.Linq的XDocument工具类来加载xml文件。其基本原理就是获取到Root节点下名为“Channel”的所有Element节点,然后使用迭代器循环,拿到每一个Element中的属性,先缓存ChannelEntity结构中,最后存到字典里。
|
C++ 编译器 Python
Shared_from_this 几个值得注意的地方
shared_from_this()是enable_shared_from_this的成员 函数,返回shared_ptr。首先需要注意的是,这个函数仅在shared_ptr的构造函数被调用之后才能使 用。
2025 0
|
JSON JavaScript 前端开发
Postman变量的使用,引入外部数据文件
Postman变量的使用,引入外部数据文件
Postman变量的使用,引入外部数据文件
|
缓存 前端开发 JavaScript
前端培训-中级阶段(23)- Manifest ApplicationCache应用程序缓存(2019-10-31期)
前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。
182 0
前端培训-中级阶段(23)- Manifest  ApplicationCache应用程序缓存(2019-10-31期)
|
Shell Linux
如何高效回退到特定层级目录?
这个脚本在经常需要切换目录,并且路径又很长的情况下,非常有用,能够快速进入到你想要的父目录。好好使用这个脚本,将会在目录切换时大大提高你的效率。
176 0
|
存储 算法 数据库