既然是概述,就没有太多详细的东西,本文主要针对asp.net开发环境。
webgame需要缓存的内容包括
1.游戏的配置信息
2.玩家的信息
对于游戏配置信息,通常是指游戏里一些固定不变的信息,例如建筑物每次升级时需要多少资源,需要多少时间等数据,这些数据当然可以写死在代码里,但通常这些数据应该放在代码外,要么是以文件形式存放(xml或者txt),要么就是放在数据库里。这部分数据的缓存很好做,只需要在应用开始时,统一做一次加载就可以了。一般来说,做过1年开发的同学都知道这种数据应该用单例模式来加载和使用,这点对java同样适用。当然做成静态属性也是可以的,只要把握好加载的时机就可以了。这里还顺便说一下,如果游戏的配置信息存在交叉访问(索引),则要注意两者之间的加载顺序。或者对交叉访问的部分不做索引,每次都动态的访问(查询)。
对于玩家的信息,则有一些说头了。基本上,现在的.net项目都做成3成结构+ORM访问。缓存的对象应该是游戏的实体对象。同上实体对象和数据库表之间都是一一对应的,这点没什么好多说的。以玩家或者村庄对象为了,它们的索引通常是ID,只需要创建对应的Dictionary<int, Player> 字典对象用来存取数据就可以了。
上面是一个基本的用于从缓存里访问玩家对象的方法。这点对大家来说,都不算很难,有点经验的同学都能写得出来。
下一步如何更新这个缓存就是这个缓存系统才是webgame的麻烦地方。
我们缓存的对象和web应用的对象不一样,它存在着随时变化的可能,并且当他发生变化时,需要能及时反馈给用户。
web应用我们以blog为例,当某位用户添加了新文章到cnblogs的首页,可能不会立即被其他用户看到,因为cnblogs首页的缓存信息还没有被修改。通常根据需要这些缓存信息可能会是1分钟,也有可能是10分钟,只有当缓存过期了以后,系统才会生成新的首页内容。其目的是减少首页的数据库查询访问量。
webgame游戏则不太一样,我花资源升级,就希望在页面上能立即看到变化,因此,当我们完成某项业务逻辑操作后,需要人工的更新资源对象的缓存。
按照通常的做法,每次逻辑操作都包含在一个事务里面,如果逻辑操作失败时,则可以对事务做撤销处理,尽量避免数据异常。
当然,这个也不是绝对的,前两天在QQ上谈论到缓存更新的问题时,某位同学帖出了他的代码,代码里,缓存的更是是在数据库事务提交之前。如果提交发生失败,则整个游戏系统已缓存的数据为主。这个问题咋一看来,和我们的思路不一样,我们就认为这样做有问题,后来回家的路上仔细的想了想,其实这样做也不无道理,因为它是在数据库提交之前更新缓存,也就是说,如果发生错误,唯一可能错误的地方就是写数据库时写失败了。但如果整个游戏系统是以缓存数据为准,只要游戏逻辑在计算时没发生错误,将错误的数据写入缓存,那么就算当前的数据修改提交到数据库失败了,数据还有可能在下一次修改时,提交一份正确的数据到数据库。整个系统不会因为数据库瘫痪了而无法运行。这点感觉和网游的服务器设计思路近似,毕竟对于网游来说,不可能每次玩家的操作都将数据写回数据库,玩家的数据都以在服务器内存里的数据为准,以定时的方式将内存数据会写到数据库。
其实这两种设计思路的差别就在于,数据是以数据库为中心还是以内存数据为中心。对与web系统来说,自然是以数据库为中心。从网游的角度来说,自然以内存数据为中心。而webgame是这两大系统的结合,其数据访问思路自然综合了这两种观点,具体到某个游戏,则需要根据游戏的需要而加以取舍了。
除了以字典为主的缓存设计外,还有一个重要的缓存对象的设计需要说一下,那就是地图。目前常见的Webgame(Travian,武林三国)都是以一张400*400的世界地图为玩家的交战地图。通常是一次性全部加载到内存里。存放的格式,自然是以x,y轴坐标为依据的二维表里。虽然首次加载是数据会比较慢一些,内存占用的空间会多一些,但当玩家查看地图页时,你会发现页面生成的数据比从数据库里获取相应数据要快很多。再加上现在服务器内存动则4G,8G的。则几十兆的地图数据还是毛毛雨了。