« 安装字体 | 返回首页 | 准备动身去厦门 »

动态加载资源

如今很多游戏engine宣称自己支持动态加载地图,也就是说可以作到跨地图时的零读取时间。听起来很高深的技术,实际不难实现,当然我们在大话西游和梦幻西游中早已经实现了。最近我正在考虑更加通用的解决方案。

先说说基本的思路。也就是我们需要把地图数据切割成小块,让每一块的数据读取解析量并不太大。然后,就可以根据玩家所在坐标读取最小数据量的数据。当玩家移动的时候,利用一些机器闲置时间去读周围的场景,或者进一步可以根据玩家移动方向把前方数据预读的优先级别调高。

其实,这个方案可以被推广到所有的游戏资源。其实,我们可以给每个资源文件都放置一个通用的数据域存放一些建议关联文件列表。如果是地图块的话,它的建议依赖文件就是它周围的地图块,或者是人为设置过跳转点的目标块。

而模型文件则可以把它依赖的贴图,骨骼文件做为建议依赖资源。地图场景文件可以建议依赖一些摆放在上面的模型文件。

有了这些依赖关系,我们在读取某个指定资源文件后,可以用一个独立线程预先加载一些可能下一步要加载数据,也可以由逻辑层主动通知一些预测信息。例如我向东向移动,可以通知 I/O 线程,东边的相关资源优先级别高一些,I/O 线程则去调整预读队列的次序。

I/O 线程的设计是比较复杂的,我的最初想法是建立一个大的 cache, 以内存页对齐(IA32 下是 4K)。如果数据被预读了,主线程索要数据的时候,用共享内存的方式,将 cache 中的数据块交换出去。

经过和同事的讨论,一个做 OS 的同事提示我,设计可以更简洁一些。因为现在 OS 对 file I/O 的 cache 机制都非常完善了,预读只需要去真的读一下文件即可,不需要再去自己做 cache,自己做 cache 只能节省一些数据 copy 的操作,但是其逻辑的复杂程度还有页表操作的负担不一定划算,所以我们只用专心做好预读逻辑即可。

这样的动态加载的资源管理模块,完全可以做的对主线程完全透明。我们的主线程只需要按阻塞模式去读取文件就够了。

但是,如果读取文件还伴随着耗时的解码过程。比如解 jpeg,解压缩,解密。那么我们最好自己做 cache 了。

Comments

我们的主线程只需要按阻塞模式去读取文件就够了。
这句话解决了我,关于如何用多线程加载大量资源的问题。感谢~

Pre-caching might be a realistic choise, together with LOD, yes Unreal Engine 3 uses this approach, and I am following those talents....

Sigh....dynamic ....streaming....background....progressive....multi-threaded map reading...How fansy...Working on it for months, still no workable stuff...It takes a genius to make that, and I am no genius....

关键是opengl或DX不支持多线程,到时候还不是把主线程停下来构建纹理等。

用一个线程载入进入视野的物件,NPC,玩家,主线程来运行逻辑. 很早就有这样实现了. 只是图素层当时比较小的时候没有好好处理, 现在太大了, 现在切换地图还得那么两三秒. 呵呵,以后就知了:) 其实想想, 如果当时把物件都放在服务器上, 圣诞等节日的时候加圣诞树之类就更加方便多了... 以后可以借鉴.

"利用一些机器闲置时间去读周围的场景"?
这个是怎么做到的?如何知道机器闲置了?呵呵,我是一个刚入门的win程序员,不是很理解.

消息并没有浪费,只是把数据分担到不同的时间段发送,频率越低的消息种类广播范围可以越远,同样距离越远广播频率越低。

方便 client 预读只是一个副产品。

而且,带宽跟 cpu, 内存一样是一种资源。总量变少了也是没有意义的,正如我们需要运行效率总是保持在一定水平,内存占用量不要长时间超过一个阀值;单位时间内的带宽减少才是最有意义的。

ps. 消息广播的 LOD 方案其实已经有采用的产品了。

你说的方法会加大服务器的负担,因为这样发的很大一部分消息是浪费的。除非是象WOW那样雷达显示角色提示(小点)的范围要比实际客户端可见的范围要大,那就可以在现有消息里面附加这个角色的显示信息(不仅限于玩家了),不然如果专门为了客户端的预读增大服务器的压力个人认为不值得

收到描述附近有玩家的数据包,和显示这个玩家并非同时发生的,中间是有时间差的。所以预读逻辑是可以提前工作的。
比如服务器先传过来的是附近500米内有哪些玩家并传递他们的装备信息,但是并不需要传递他们的坐标和行为逻辑。等到 100米(游戏视距)内后,简单传一下玩家id 和坐标,动作即可,装备这些东西并非经常变化的。

替代资源的方式很常用,这个在脚本中就可以处理了。

象地形的贴图这样的数据比较容易预测,但象主角相关的资源就没法预测了,因为你有可能在野外走突然就看见了一群其他玩家,不可能把所有职业的所有换装资源都扔在内存里,如果实时的以阻塞模式去读取又会突然卡一下。所以只能把需求丢给资源线程,主线程压后一段时间再显示(实际上角色进入同屏表一般都比较远,除非正好在附近上线)。这样要解决的是如何在资源暂时不可用(部分或全部)的情况下显示不至于出错

Post a comment

非这个主题相关的留言请到:留言本