一不注意,在Unity3D中DllImport 引起的Bug.

摘要:
然而,事情并不是那么简单。像这样的正常进程是可能的:AddPluginPathToEnvironmentPath();解密资产();但是,这不起作用:DecryptAsset()//DllNotFoundExceptionAddPluginPathToEnvironmentPath();解密资产();//StillDllNotFoundException的原因是DecryptAsset函数是DllImport。第一个调用将查找和加载非托管DLL,并在内存中查找函数的地址。此时,在Path中找不到DLL,因此只能找到DllNotFoundException。但是,DllImport不会再次查找Dll,因为它直到第一次才查找Dll。所有后续调用都将调用缓存。这里涉及两个知识点:1.Unity中的脚本执行顺序不正确2.DllImport缓存调用方法

单要说这个Bug是很简单,但是得从头说起。

 一些大型的网络游戏,或者加载比较多的一些场景时,如果要等待所有模型,贴图等各种资源文件加载完毕才能执行游戏,对用户将会是一个很头大的事情。所以就需要用到动态加载,即AssetBundles。

引用自:http://bbs.9ria.com/thread-214663-1-1.html

AssetBundle基本概念就如上面所讲,虽然我正开发的项目不是大型网络游戏,但是也涉及到在线更新,所以也使用到AssetBundle。准确说是动态加载。

项目最初没有使用动态加载,所有的资源都放在场景中。随着项目的不断发展,更新越发频繁,也发现了问题。

每次都是用Unity3D自带的Build(File->Build&Run),你会发现Unity很好心地将很多零散的资源整合在一起,分批打包到不同文件(sharedassetsX.assets)。

然而这些 *.assets 并没有什么规律,以至于有时候你只替换了一张小图,也可能导致整个项目需要重新更新。【尽管是PC,但是AndroidBuild 也存在同样的问题】

所以大概在半年前,在项目中实现了基本的动态加载资源功能。

但是使用AssetBundle来实现动态加载的话,那些资源如何才能可视化呢?例如一张图 需要加载进来后才能调大小、摆位置。从网上找的AssetBundle 有关的文章都没说到这个,也有可能是作为公司的机密没公布出来。

如何既方便可视化编辑,又方便动态加载呢?

大概的思路如下:

Launcher:

1.从服务器下载资源文件到指定文件夹(Dir)

Editor:

1.检测是否存在需要动态加载的资源(通常是Ngui)

2.对需要动态加载的资源AddComponent<Loader>

3.Loader.setPath = 当前资源的路径

4.打包当前资源( Prefab->AssetBundle->EncryptionZipDir-> UnloadToServer)

5.当前Ngui.资源(Texture) = null

6.Build 

Loader:(Player 加载)

1.遍历Scene 中所有Loader

2.Ngui.Texture = GetResource(Launcher制定目录+Loader.Path)

然而在实现过程中 原先可以运行的游戏(初步实现时可以) 在一大轮魔改之后不行了,而且是只有在使用自己的方法Build就有问题,而使用Unity自带的Build就没问题。问题是某个DLL无法加载(DllNotFoundException),而更糟糕的问题是在某些机台上可以运行,而某些机器却抛出DllNotFoundException。

除此之外还由于加载未完善导致句柄泄露,资源未整理完毕(大部分资源存在透明空白,浪费空间和加载时间),还有项目的其他进度紧张,导致这部分被暂停了下来。

到了今天(170216)稍有时间,再仔细查了下这个问题,万万没想到查找这个问题却整整用了我一整天!

刚开始时,我以为是Editor中第五步 导致Unity出现怪异的Bug(所有问题首先别怀疑是自己的错误!逃),所以精简了Build场景后(又10多个减少至1个,方便发现问题),分辨使用我写的Build和Unity自带的Build生成了目标文件(假设分别为A和B)。

然后逐步使用B_Data中的文件逐步替换A_Data中的文件,看看是那些文件导致DllNotFound的发生。最终发现只要把"mainData"和"resources.assets"替换后就不会出现问题了!然后使用对比工具逐步对比两个项目中的这2个文件。。。然而我还是太天真了,对比了1个多小时,发现这应该不是主要原因。

然后只能转换思路,逐步减少自己写的Build步骤(二分注释法 - -),最终发现只要场景存在Loader脚本,则有可能发生DllNotFound的情况!原来元凶在这!

经过最终分析元凶 解密资源时需要用到某个DLL的算法进行解密,然而此时却并没对此Dll的路径增加到环境变量path,所以发生了DllNotFoundException。

然而事情并没这么简单,如这样正常的流程是可以的:

AddPluginPathToEnvironmentPath();
DecryptAsset();

但是这样却不行:

DecryptAsset(); //DllNotFoundExcepion
AddPluginPathToEnvironmentPath();
DecryptAsset(); //Still DllNotFoundExcepion

其原因在于DecryptAsset 函数是DllImport的,第一次调用时会查找和加载非托管DLL并查找函数在内存中的地址。而此时并没有在Path中找到该DLL,所以只能 DllNotFoundException。

但是按道理,在增加DLL路径到Path后,第二次调用揭秘应该成功才对。而DllImport 并没有重新查找一次Dll,因为第一次才会查找,以后调用都是调用缓存。只要没有找到这继续DllNotFoundException,不会重新查找。

所以只能是 调用 AddPluginPathToEnvironmentPath 后方能调用 DecryptAsset 方法。

而鉴于我项目的特殊性, 将 AddPluginPathToEnvironmentPath 和 DecryptAsset 写在不同脚本的 Start 方法中,由于Unity没有明确说明脚本调用顺序的话,是对脚本的Start顺序随机调用的,所以导致有些机上可以成功但另外的DllNotFoundException。

这里涉及到2个知识点

1.Unity 中的脚本乱序执行

2.DllImport 对调用方法做了缓存

免责声明:文章转载自《一不注意,在Unity3D中DllImport 引起的Bug.》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇批量实现ssh免密登录ES6 (9):iterator 遍历器下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

理解Android编译命令(转)

一、引言 关于Android Build系统,这个话题很早就打算整理下,迟迟没有下笔,决定跟大家分享下。先看下面几条指令,相信编译过Android源码的人都再熟悉不过的。 source setenv.sh lunch make -j12 记得最初刚接触Android时,同事告诉我用上面的指令就可以编译Android源码,指令虽短但过几天就记不全或者忘记...

微服务SpringCloud容器化案例

前言 当我们在使用微服务的时候,那么有一个问题一定会困扰我们,那就是项目的测试和部署。因为在单体应用下,部署项目很简单,直接打包启动就可以了,而对于微服务来说,因为有各个组件的存在所以让测试和部署都变得很麻烦,而容器化是微服务的部署一把利剑。 PS:本文不介绍具体docker使用的各种基础,以及微服务的各种基础,就是给出相应的案例,你可以根据这样的案例快速...

从屏幕刷新频率到Unity VSync

显示器有一个属性叫屏幕刷新频率,它是指每秒刷新屏幕的次数,单位为Hz,一般设置为60Hz。 什么是刷新屏幕呢?我们屏幕是由像素矩阵组成的,其(CRT)显示图像的原理是靠电子束从左到右、从上到下逐行激发屏幕内表面的荧光粉单元(像素)来实现的。电子束一次水平方向的扫描叫行扫描,一次完整的扫描就是刷新屏幕,形成的图像就是一帧。因此60Hz的刷新率也就是每秒60...

SPEC CPU——简介和使用

前言 SPEC CPU是一套行业标准的CPU密集型基准测试套件。SPEC设计了此套件,以使用实际用户应用程序开发的工作负载,在最广泛的实际硬件范围内提供计算密集型性能的比较度量。这些基准作为源代码提供,要求用户习惯使用编译器命令以及通过控制台或命令提示窗口通过命令解释器使用的其他命令,以便生成可执行二进制文件。 SPEC CPU2006和SPEC CPU2...

Unity_AssetBundle笔记_(一)(俗称AB包_个人笔记欢迎指正)

AssetBundle_介绍   (基于unity 2017 版本 --- 如要知晓最新资料建议去看官方文档)(最近看到的一篇AB不错的文章:https://blog.csdn.net/Mars___Z/article/details/90199004。简明扼要) 一: AssetBundle的定义和作用    用处?    1,AssetBundle是一...

Unity 数字孪生笔记 工具介绍

流程思考 数字孪生本质上一种基于实际物理数据的可视化方案,通过对接实际数据,在三维界面中展示孪生结果。那么这个流程就很简单了。整个流程分为三块:数据来源-》数据分析-》数据展示 输入数据 首先我们需要考虑我们能拿到什么。第一,实际物体的三维数据从哪里来,第二,实际数据怎么获取到。 模型数据 工业上常常会用到CAD模型,CAD模型具有精确、统一的特点,但...