目前公司以开发网页游戏为主,这里就从游戏场景说起。
场景描述:
游戏简化版是这样的,游戏分为养成和战斗,玩家通过不断的战斗获得战利品并升级自己,然后挑战更强力的BOSS,貌似一般游戏都这样!
那么我们就有了2个场景,玩家面板和战斗面板。
玩家面板有几个数据:玩家名字,当前金钱,当前等级,当前经验,装备武器,背包。
战斗过程不说:战斗会玩家会获得经验和物品或金钱。
传统的B/S开发模式。
一般项目都采用传统三层模式,虽然我不喜欢这种模式,觉得比较繁琐,但是我加入之前公司的项目确实是采用这种模式开发。
简单的描述下开发过程:
1.首先定义一张玩家表:
玩家ID,玩家名字,金钱,等级,经验
2.然后有张背包表:
物品ID,玩家ID,装备位置ID
定义好对象,或者通过ORM工具,我们就拥有了 玩家类,和道具列表
场景:
玩家装备了一把剑,然后去战斗,接着获得一些金钱和装备。
UI流程-》玩家面板-》背包面板-》装备武器-》进入战斗(略过)-》结算面板-》返回玩家面板
开发过程是这样的:
1.首先我们需要玩家面板的一个数据请求,我们定为“请求玩家信息服务”
2.然后我们需要一个背包面板,“请求玩家背包服务”
3.战斗后结算信息,“战斗后结算服务”
看看都干了什么?
服务端:
1.查找玩家数据,然后通过“请求玩家信息服务” 返回,包含{名字,金钱,等级,经验}
2.查找玩家背包数据,然后通过“请求玩家背包服务”返回,包含一个道具列表 [{ 道具ID,装备位置ID}]
3.战斗后返回战斗结算服务{金钱,经验,[道具1,道具2]}
客户端:
1.请求 “请求玩家信息服务”并绑定到面板。
2.请求 “请求玩家背包服务”并绑定到面板。
3.战斗后,显示结算数据。
4.第一个面板,执行第一步。
这个简单,看起来没有问题。
然后我们增加了几个新的需求:
1。我们需要在背包面板中显示金钱
两个做法:
1.在请求背包服务器中,返回金钱数据。
2.独立一个金钱服务。
2。如果我们需要在战斗中有个小面板,显示玩家拥有的等级,经验,以及拥有的药水
简单:
一个“战斗中服务”,返回 { 等级,经验,药水数量 }
回头看看,2个服务都需要金钱,2个服务需要等级、经验
独立出来?有个服务叫获取金钱、有个服务叫获取等级经验?
我们有了如下假设1:
如果有个服务,叫:“刷新玩家数据”返回 整个玩家数据 { 名字 ,金钱,等级,经验,背包[{道具ID,装备位置ID}]}
这个完美了,只要能刷到任何数据,我们就能省下几个服务:
1.“请求玩家信息服务”
2.“请求玩家背包服务”
3. “战斗中服务”
就省下2个服务:(看起来爽多了,而且仅需要解析一个)
1.“刷新玩家数据”
2. 战斗后,显示结算数据。
看起来这是一个简化服务的文章么?
以上的假设在理论上是成立的,但是总是刷新真个数据太大了对吧。
然后我们有了第二个假设2:
如果这个服务能根据我的需求返回响应的数据就更好了。
比如一些过滤写法:ret=金钱|等级|经验 (我们实现过。。)
看起来很完美吧。
这个有些致命的问题:
1.客户端需要知道什么时候应该刷新什么。
2.如果需求更改,需要修改相关的请求过滤。
额,第三个假设3:
如果我们客户端有个服务端相关对象的镜像副本,并且能保持同步。
那么是否能解决假设2的问题?
看起来很完美,我们需要解决的问题?
1.如何定义对象?
这个比较简单,我们采用服务端先定义,然后采用反射生成客户端对象定义数据。
2.如何同步?
这是本文的重点了:OpLog 协议
OpLog 协议:
OpLog 我这边称他为操作日志,搜一下Mongodb的OpLog,理念还是比较类似的,OpWeb便是基于此同步理论做的。
Mongodb的节点间数据同步就是基于OpLog,而OpLog Engine原本出发点用于分布式节点中,内存对象的实时同步。
但是该项目没有完成(甚至没有怎么开始。。)
我们采用Json数据用来存储并同步数据,Json以灵活快捷著称,并且较小的体积,正是我们需要的。
1.对象定义,玩家
{ 金钱,经验,等级,背包 [ { 道具1,道具位置1 }, {道具2,道具位置2} ]}
2.如何定位对象,比如我需要修改金钱:
{ 金钱 : 100 }
但是我比如需要修改 背包中, 道具1的道具位置1?
背包->[0]-》道具位置1 : 10
好像不太合适,比较深的层次呢?
假如我们的对象永远都只有1层,所有对象都必须拥有一个ID,定义变成这样:
{ ID :1000 ,金钱,经验,等级,背包 [ {ID : 1001 ,道具1,道具位置1 }, {ID:1002, 道具2,道具位置2} ]}
我们修改金钱变成:
{ID : 1000, 金钱 : 100}
修改 背包中, 道具1的道具位置1?
{ID:1001,道具位置1 :10 }
我们从根目录遍历,就能找到ID为1001 并且完成修改,完美!
以下是我们完整的协议说明:
{
Ts:时间戳,所有的操作时间戳必须前进(也就是必须大于前一个)
Op:Sync,Update,Insert,Remove(4种状态)
Rid: 操作的对象父Id
OpStr:Op=Sync则为整个对象内容,
Op=Update,则为差异内容,
Op=Insert ,则为子对象内容,
Op=Remove,为空
Ns:当Op=Insert Op=Remove时有效,列表的字段名(如上例,添加一个武器 Ns:包裹
Oid:当Op=Insert Op=Remove时有效,子对象OpId
}
(当Op=Sync时,直接覆盖OpStr到当前对象)
添加一个对象:
{ Op:Insert ,Ts : 10001,Rid:1000,OpStr : 新建对象{ OpId :1003,数据1 :10 },Ns:列表,Oid:1003}
删除刚才对象:
{ Op:Remove ,Ts : 10002,Rid:1000,Ns:列表,Oid:1003}
更新一个对象:
{ Op:Update ,Ts : 10001,Rid:1000,OpStr :{数据1 :10 } }
开源OpWeb框架介绍 请移步: http://blog.csdn.net/icesun963/article/details/17194193