Silverlight MMORPG WebGame游戏设计(六)-----Server和Client的婚后协议[附上完整15M游戏DEMO]

        上回说到Server少爷和Client小姐好不容易踏入婚姻的殿堂,洞房花烛之夜,Client小姐却要Server少爷签下婚后协议。Server一脸不快:“都一家人还签什么协议啊?”Client道:“你们男人啊,就是花心,不看紧点,不知道跑那野去了。为了以后我们能琴瑟相合,还是签了协议的好。”Server呵呵一笑:“好老婆,那就签吧,你开心的时候,我就陪你开心;你不开心的时候,我会哄你开心...”一番话哄得Client心花怒放,看着Server写完“奴隶宣言”,拿到手里仔细查看,却见Server写到:

       

  public enum WifeCmd
  {
         哄老婆开心,
         上交工资,
         陪老婆逛街,
         带老婆去兜风
         ......
  }

 

 Client看到这里,笑颜如花,连enum都用上了,真是个好夫君,这美满的婚姻也真是来之不易。

 

         -----------------------------------------------分割线,以上Server和Client的爱情剧完美剧终---------------------------------

          前五章,我们用讲故事的方式把Server端和Client的通讯机制讲解了下。此后我们要在此基础上开始我们的Web传奇的开发之路,让我们感谢Server和Client的精彩演出。

          每一个玩过传奇的人都记得那古朴的登录画面,当我们输入账号和密码,点击登录,随着铿锵的击鼓声,一扇石门徐徐而开,一个游戏的世界在向我们召唤,让我们赶快开启我们的传奇之旅吧!!

          游戏的开始,我们需要注册账号。这账号数据放在那里呢?放客户端,显然不可能,用户数据太不安全了。只好放服务端了,再说用户账号数据可是很重要,那些网游公司为此争得头破血流。经典的案例那是网易从九城夺取“魔兽世界”的代理权,期间坎坎坷坷,勾心斗角,俨然一部商业大片。还是“魔兽世界”的开发公司暴雪大神有远见,所有的用户数据都是属于暴雪的,这500W用户账号是属于暴雪公司的,数据库里的这些数据早就在停服前被暴雪的技术人员备份走了。

          所以说我们做Web传奇也要有远见,这个账号信息呢,还是归我williams所有吧,我把它们都储存在Sql Server2005数据库里呢。

          一张简单的账号表如下:

             

账号信息表 Users

字段名称

数据类型

含义

约束

UserID

int

 

 

UEmail

Nvarchar(32)

 

 

Upwd

Nvarchar(16)

 

 

UaddTime

DateTime

 

 

Ubalance

int

用户账号金额,用来消费

 

UloginTime

DateTime

 

 

UloginIP

Nvarchar(32)

 

 

Ustate

int

账号状态

 

          

           看到这里,你们会说这咋个和做网站的差不多呀?反正也不用忽悠大家,WebGame上的注册和网站注册有啥区别呢?本质上没什么区别,不就是把用户输入数据写到数据库里。

           用asp.net做过网站的都知道,做一个注册页面很简单,双击按钮写事件,调用BLL层的方法,执行insert语句就OK。但是在silverlight里,客户端不能直接和数据库打交道,怎么办呢?

           如果你看了前五章,你很容易想到客户端可以把用户数据放到byte[]数组里,封装到一个Message里发给服务端就可以了。服务端收到这个Message,判定后再调用BLL层的方法执行Insert语句也就可以了。和asp.net网站不同的是,在silverlight WebGame里数据是从Silverlight客户端发送到服务端,而在网站里数据是通过表单提交到Web服务端,asp.nett网站表单提交数据的过程作一个asp.net程序员可以不关心是怎么传递的,但是对于silverlight客户端来说,由于选用了原生态的Socket的通讯方式,我们得了解清楚些。

           看到这里,你可能豁然开朗,前五章讲的那肉麻的爱情故事就是为了方便的传递数据啊。哎,谁让我们这些asp.net程序员比较少接触到Socket通讯方式呢,我也是花了一周才看个明白点。

          罗嗦了这么多,让我们开始设计界面吧,我这个人很喜欢怀旧的,也没有美术功底,就把传奇里的界面搬来了,我在这里特此声明:本教程只供学习研究,所有素材来自网络,请勿跨省,勿发律师函。

        

        注册界面:

        

 

我们先来完成注册界面的功能,玩一个游戏,如果不注册个账号,是没办法登陆进去的,玩过游戏的都知道。

 

 void btnReg_Click(object sender, RoutedEventArgs e)
   {
            Users user 
= new Users { UserName = this.txtUserName.Text, Upwd =GameCMDFormat.HashFormat(this.txtPwd.Password), Uemail = this.txtUserName.Text, Ustate = 1 };
            MessagePool.AddSendMessage(GameCMDFormat.CreateNewUser(user));
//把发送的消息放到消息队列里
     }

 

 ①这里我们用一个User对象来保存了用户注册数据,这样才显得OO一些。

 ②这里我们写了一个GameCMDFormat类来产生Message对象

 

 

   /// <summary>
        
/// 新建账号命令
        
/// </summary>
        
/// <param name="user"></param>
        
/// <returns></returns>
        internal static SocketClient.Message CreateNewUser(Users user)
        {
            
return new SocketClient.Message(Convert.ToByte(GameCmdEnums.CreateNewUser), 1, System.Text.UTF8Encoding.UTF8.GetBytes(SerializeUtil.Encoder<Users>(user)));
        }

 

 

        让我重点来介绍下这个GameCMDFormat类,以后我们的命令基本上都是这个类帮我们产生的。

        在构造返回的Message对象时,第一个参数是class参数,我们用来存放命令的类型,这里我们用到的就是enum,这就是我们的server少爷和client小姐签婚后协议用到的。女人都喜欢男人专一点,enum值是唯一的,刚好满足女人的要求。当然这协议嘛,男方女方手里都有一份才算有效。所以server端有这样的enum,client端也会有这样的enum

        

 /// <summary>
    
/// 客户端的请求,或服务器发给客户端的命令
    
/// </summary>
    public enum GameCmdEnums
    {
        
/// <summary>
        
/// 注册新账号
        
/// </summary>
        CreateNewUser,
    }
     
/// <summary>
    
/// 服务器执行结果
    
/// </summary>
    public enum GameCmdResult
    {
       CreateUserTrue,
       CreateUserFalse, 
    }

 

 

       这协议一式两份,童叟无欺,大家都看得明白,无可非议,客户端端告诉服务端: CreateNewUser,服务端拿来相同的enum一比对,哦,原来是要我去建一个新账号,那好我就把新用户数据写入到数据库。写完了,服务端发送一个Message给客户端,这个Message带的命令是CreateUserTrue,客户端拿来enum一看,哦,账号建立成功了。

  

 

        ③这里我们用了SerializeUtil.Encoder<Users>(user)方法,这里用的是json序列化,为什么要用json序列化呢?你想啊,一个User对象,我怎么好放到byte[]数组里,这个比较难,不太好描述。如果你想想我们在.net里的序列化,我们可以把一个对象变成xml数据或者二进制流。

       但是很多平常在.net framework里使用的序列化和反序列化帮助类(如System.Runtime.Serialization命名空间下的许多类和方法)在SilverLight下都不可使用了。谁让silverlight是个精简框架呢。

       查下资料发现

       Silverlight可以用序列化,但是不能直接使用,必须通过服务来调用,比如WCF和Web Service。

       Silverlight 内置支持WCF的 DataContractSerializerDataContractJsonSerializer 两种序列化方式,也可以用System.Xml.Serialization 里的  XmlSerializer

       一般的过程是,通过服务提供序列化的对象,然后Silverlight调用服务获得这些对象。

       请参考:Silverlight中的序列化

 

       不过我们这里用的是socket,以上的方式不适合了,还有XML序列化的结果比json的数据量要大不少,为了减少通讯量,在描述同样数据的情况下我选择了json序列化,我在网上我找到了一个.net下的 json序列化组件:

       Json.NET.

      使用了里面的两个方法:

 

    /// <summary>
    
/// 对象序列化和反序列化,Json序列化
    
/// </summary>
    public class SerializeUtil
    {
     
        
/// <summary>
        
/// 序列化
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <param name="data"></param>
        
/// <returns></returns>
        public static string Encoder<T>(T data)
        {   
            
return JsonConvert.SerializeObject(data);
        }
        
/// <summary>
        
/// 反序列化
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <param name="data"></param>
        
/// <returns></returns>
        public static T Decoder<T>(string data)
        {
            
return  JsonConvert.DeserializeObject<T>(data);
        } 
    }

 

 

  这样我们很方便把一个对象放变成string,再把string用 System.Text.UTF8Encoding.UTF8.GetBytes()方法变成byte[]存放到一个Message对象就可以了。

       ④我们用到了自己写的消息队列类MessagePool类里的AddSendMessage方法。

          至于为什么要用队列来储存发送的消息,这是由于MMorpg客户端和服务端交换数据很频繁,大量的数据如果拥塞在一起发送就不太好,你说我们中国人就是多,春节买火车票如果我们不排队,都挤到售票窗口去抢,那不乱了套么?

          在MessagePool类里,我用了多线程发送,这里就涉及到了队列queue<T>的线程不安全问题,如何保证线程安全,就要用到了lock锁定,至于是否会影响效率,JeffreyZhao在一篇文章里说,也许lock的影响微乎其微,我没有做实验来判定,有兴趣的同学检验下。

          可能对于一些.net初学者来说在多个线程中保证queue<T>的线程安全不太好理解,那就多查查资料吧,我也是查资料,花了些时间写好的。

         当然,客户端发送数据的同时,也是要接受数据的,所以MessagePool类里有发送队列也有接受队列。

         对于MessagePool类我这里就不多讲了,留着专门一节再讲消息队列。我们本节的重点是要完成注册的过程。

 

      以上四点只是为了说明我们要把一个Message对象组装起来放到消息队列里中间的过程也不简单,涉及到队列,序列化,线程安全,做游戏不容易,反正我觉得比做网站要难一些。

 

      好了,我们折腾了这么久,那么服务端接收到这个客户端发送的这个消息后会这么做呢?

 

   /// <summary>
        
/// 执行客户端发送来的请求
        
/// </summary>
        
/// <param name="cmdstr"></param>
       internal static Message ExcuteCmd(int type, int flag, string cmdstr,System.Net.Sockets.Socket clientSocket)
       {
           GameServerCmd cmd 
= new GameServerCmd();
           GameCmdEnums t 
= (GameCmdEnums)Enum.Parse(typeof(GameCmdEnums), type.ToString());
           
byte[] content = UTF8Encoding.UTF8.GetBytes(".");
           
switch (t)
           {

               
case GameCmdEnums.CreateNewUser:
                   {
                       
int userID = 0;
                       
if (cmd.CreateNewUser(cmdstr))//执行注册命令
                       {
                           
return new Message((byte)GameCmdResult.CreateUserTrue, (byte)userID, content, clientSocket);
                       }
                       
else
                       {
                           
return new Message((byte)GameCmdResult.CreateUserFalse, (byte)userID, content, clientSocket);
                       }
                   }

               }

 

GameServerCmd 这是个命令执行类,它调用了BLL层里的方法。

 

  /// <summary>
        
/// 注册新账号
        
/// </summary>
        
/// <param name="cmdstr"></param>
        
/// <returns></returns>
        internal bool CreateNewUser(string cmdstr)
        {
            Users user 
= SerializeUtil.Decoder<Users>(cmdstr);
            
if (UsersCtrlBase.Instance().CreateNewUser(user))
            {
                
return true;
            }
            
else
            {
                
return false;
            }
        }

 

        写入账号信息到数据库后,然后发送一个注册成功的Message对象,我们也把它装到服务端的消息队列里等待发送给客户端,在服务端同理我们也有接收队列和发送队列,服务端接收和发送的队列是客户端的N倍,你可以近似估计N为客户端的个数,如果一个服1000人,那么就至少是1000倍于客户端。不开多线程,服务端估计是不能快速处理完这些数据。写到这里我想到,现在服务端早就是多核了,是不是要在服务端要到多核编程呢?把服务端多核优势发挥出来。这就留给大家去实现吧,我也是要花些时间研究下多核编程的。

           不小心写了这么多,我喜欢写游戏,去年我下班后吃完饭就写Web传奇,中间遇到不少的困难,一路摸索,是梦想支撑着我,前方困难重重,我们只有披荆斩棘,努力前行。

           我说过这篇文章里,我要把Demo提供给大家,由于持续花了近3个月的业余时间,写的代码有点多,从创建人物到下载数据,保存数据,合成地图,人物,怪物,再到即时的PK,中途还写WPF的地图编辑器,一下子把这些东西都发出来,估计看得也是头痛。我就一步步把这些代码精简出来吧。

           下载文件列表:

           1.数据库设计文档           2.json.net组件

           3.MyMirWebGameDemo1

           4.MyMirWebGameDB.

           5.怪物数据包   (重要:请放在MyMirWebGame.Web项目的clientbin里的Data文件夹下)

          有兄弟反应MyMirWebGameDemo1无法下载,我做了分包文件。

           MyMirWebGameVS2010D.part1         

           MyMirWebGameVS2010D.part2

           MyMirWebGameVS2010D.part3

           MyMirWebGameVS2010D.part4

        

Demo框架机构图:

                 

Demo运行提示:

                 1.附加MyMirGameDB数据库

                 2.修改MyMirGameServer里的app.config里的connectstring数据库连接字符串

                 3.启动MyMirGameServer项目里bin/debug里的MyMirGameServer.exe程序

                 4.在IIS里hostMyMirWebGame.web站点。

                 5.账号 w,密码1;账号xiangwei,密码:1,当然也可以注册账号

                 6.游戏只实现了男战士职业,只完成了物理PK过程

                 7.只做了人物之间的PK互动,人与怪物间的PK互动还没写完。

Demo的客户端已经升级到SL4,建议使用vs2010,并下载 Silverlight 4 Tools RC2 for Visual Studio 2010.

Demo测试环境:win7+ms sqlserver2005+silverlight4;

                    局域网测试通过,感谢以前在武汉创美的同事们。

                    互联网测试通过,感谢"深蓝WPF/Silverlight(群号:73068105)"群里的兄弟们。

申明:Web传奇客户端代码是在“深蓝色右手”silverlight 游戏引擎基础上开发做了30%左右的变动,特此申明。

备注:代码文件已经上传,附上PK画面:

          

 

   本文版权属于williams所有,首发http://www.cnblogs.com/,转载请注明出处。
posted @ 2010-05-09 01:14 王传炜 阅读(3297) 评论(33) 编辑 收藏

 回复 引用 查看   
#1楼2010-05-09 01:31 | dongzz      
深夜发帖辛苦了!
 回复 引用 查看   
#2楼[楼主]2010-05-09 01:35 | 王传炜      
@dongzz
呵呵,文章写着写着就这么晚了。

 回复 引用 查看   
#3楼2010-05-09 10:28 | fishkuro      
good guy
 回复 引用 查看   
#4楼2010-05-09 11:22 | MagicHu      
你可以和深蓝同志交流交流
 回复 引用 查看   
#5楼2010-05-09 11:23 | MagicHu      
原来交流过了,不好意思。
 回复 引用 查看   
#6楼[楼主]2010-05-09 11:27 | 王传炜      
@MagicHu
我也是看深蓝色右手的系列文章从去年9月份开始写的。

 回复 引用 查看   
#7楼2010-05-09 11:56 | 韩倾城。      
@dongzz
王老师,强烈无比的支持, 我也对webgame感兴趣了,不过我在学着用flex做flash的RPG,源码下下去学习下算法

 回复 引用 查看   
#8楼2010-05-09 11:59 | 韩倾城。      
王老师,强烈无比的支持, 我也对webgame感兴趣了,不过我在学着用flex做flash的RPG,源码下下去学习下算法
 回复 引用 查看   
#9楼2010-05-09 12:25 | 神魔神威      
好有深度的文章啊!
值得研究学习!

 回复 引用 查看   
#10楼2010-05-09 12:37 | pser      
Good job
 回复 引用 查看   
#11楼2010-05-09 13:11 | 信息化工作室      
想学习下,但是MyMirWebGameDemo1 下载不了呀,能不能传到其他地方呢,比如CSDN呢。或者分包上传上来,感谢呀。
 回复 引用 查看   
#12楼[楼主]2010-05-09 13:17 | 王传炜      
@信息化工作室
可以下载的啊

 回复 引用 查看   
#13楼2010-05-09 14:35 | 绵白糖      
盼来了博主您的新篇 激动啊
 回复 引用 查看   
#14楼[楼主]2010-05-09 14:41 | 王传炜      
@绵白糖
谢谢关注,有兴趣可以在次基础上继续写

尽管看的有点晕,不过觉得还是很不错的文章!!!!!
 回复 引用 查看   
#16楼2010-05-09 23:49 | 一杯苦茶      
我要来顶楼主的,正是我所需要的,谢谢无私的奉献
 回复 引用 查看   
#17楼2010-05-16 19:57 | 淡蓝的自由      
Error 1 Source file 'D:\webgame\SL\mygame\Component\Enumerations\DownLoadTypeEnum.cs' could not be opened ('未指定的错误 ') MyMirWebGame

出现这个问题,对不起我是新人,请赐教

 回复 引用 查看   
#18楼[楼主]2010-05-16 20:12 | 王传炜      
@淡蓝的自由
DownLoadTypeEnum.cs 是mymirwebgame项目外连接到Components里的,我本来想共用一个类文件的。你可以把DownLoadTypeEnum.cs复制到mymirwebgame里,删除那个带快捷方式的文件

 回复 引用 查看   
#19楼2010-05-26 01:22 | ng      
很奇怪啊,运行客户端后,一直loading在:获取文件列表。没有任何反映,就是在显示那个加载进度条,显示获取文件列表。。。进不了主界面
 回复 引用 查看   
#20楼2010-05-26 01:33 | ng      
楼主,你是不是忘记放那个data文件夹下的Mask.zip文件了,我执行到那里的时候出错了,就是到获取文件列表的时候出错。不知道是不是由于这个原因所造成的
 回复 引用 查看   
#21楼[楼主]2010-05-26 10:29 | 王传炜      
@ng
上次是忘了放mask.zip文件,已经补上了这个文件

 回复 引用 查看   
#22楼2010-06-19 22:22 | cct      
为什么新注册用户进去后会是个空白的页面,用老用户的时候,鼠标放到下面的小按钮的时候也会整个页面变成空白,难道是我的程序部署问题?期盼能帮我解答,谢谢!
 回复 引用 查看   
#23楼[楼主]2010-06-21 16:19 | 王传炜      
@cct
注册的时候只能选男战士职业,其他职业没有皮肤文件。还有放到下边的小按钮报错是因为一段XAML标记从3.0升到4.0时报错,你把项目编译成sl3.0就可以了。

 回复 引用 查看   
#24楼2010-06-22 14:33 | cct      
@王传炜
谢谢回复。一会试试 :-)

请问楼主还在继续这个系列的开发么?希望能见到更多的文章。

 回复 引用 查看   
#25楼2010-09-03 17:15 | 剑灵      
王老师,压缩包中少了WpfMapEditer项目,是不是有意删除的?
 回复 引用 查看   
#26楼2011-02-20 22:26 | 银光照钒粉      
谢谢王老师的无私.
再问一个问题我怎么总是显示联不上服务器呀。我将MyMirGameServer和MyMirWebGame.Web设为启动项还须要设置什么吗?

 回复 引用 查看   
#27楼[楼主]2011-02-21 15:30 | 王传炜      
@银光照钒粉
你要单独启动MyMirGameServer.exe,数据库什么的都要先配置好。

 回复 引用 查看   
#28楼2011-03-05 08:55 | 注册名      
Williams,请原谅我并不知你的姓名。我想根据你的如今版本基础演绎成一个新作品,只做学习研究Silverlight之用,遵循创作共用版权协议,您看,可以吗?
 回复 引用 查看   
#29楼[楼主]2011-03-07 11:41 | 王传炜      
@注册名
可以的,那需要你花不少的功夫来完善它,希望看到你更好的版本。

 回复 引用 查看   
#30楼2011-04-28 09:58 | 30767856      
怎么少了地图编辑器呢?
 回复 引用 查看   
#31楼2011-04-29 10:47 | 30767856      
王老师,压缩包中少了WpfMapEditer项目,是不是有意删除的?

 回复 引用 查看   
#32楼[楼主]2011-05-20 16:02 | 王传炜      
@30767856
是啊,编辑器带图片太大了。再说编辑器写得也不够好。

 回复 引用 查看   
#33楼2011-06-21 17:36 | Kisszoo      
您的文章给了初学者很大的帮助,谢谢了