Silverlight MMORPG WebGame游戏设计(七)-----IsolatedStorage,想说爱你不容易

        在我开始写Web传奇的时候,就在想一个问题:如果我把所有的地图,怪物图片,音效等游戏资源都放在XAP包里,这个XAP包就会越来越大。在我很早以前玩传奇2的时候,安装包就300多M,后来传奇3就有1G多了。如果等我的web传奇越写越大的时候,那我的游戏需要loading多久啊,玩家可等不了。所以我把微软的文档找来,发现有独立储存区域这个东西,微软的解释如下:

        

     通过使用独立存储,数据将始终按用户在虚拟文件系统中隔离,虚拟文件系统可以是根目录中的一个文件,也可以是一个目录和文件树。 
     独立存储数据舱是一个抽象的存储位置,而不是一个具体的存储位置。它由一个或多个独立的存储文件(称为存储区)组成,这些存储文件包含存储数据的实际目录位置。任何类型的数据都可以保存到存储区中。 

 

       

          于是我就有这样的设想:

           1.把游戏所需的资源从服务端下载silverlight客户端的独立存储区域里。这样游戏客户端第一次下载完毕后,下次登陆就不用下载这些资源了,可以很快的进入游戏。

           2.按每个地图分别做成不同的zip包,如果开新的地图只需要在服务端放上新的地图包,在客户端登陆的时候通知其下载就可以了。

           3.xap包里的资源尽量少,除了必要的dll文件,其他都不放,这样我们就能把xap包控制在300K以内,客户端loading的速度就很快了。

 

           根据微软的silverlight3文档,我写了一个独立存储区域资源读写类

 

ExpandedBlockStart.gif IsolatedStorageUtil
  ///   <summary>
    
///  独立存储区域操作类 by williams
    
///   </summary>
     internal   class  IsolatedStorageUtil
    {
        
#region  私有成员
        IsolatedStorageFile store ;
        
internal   long  availableFreeSpace;
        
internal   long  totalSpace;
        
#endregion

        
#region  构造函数
        
internal   IsolatedStorageUtil()
        {
            store 
=  IsolatedStorageFile.GetUserStoreForSite();
            availableFreeSpace 
=  store.AvailableFreeSpace;
            totalSpace 
=  store.Quota;
        }
        
#endregion

        
#region  操作方法
        
///   <summary>
        
///  增加新的空间
        
///   </summary>
        
///   <param name="spaceSize"></param>
         internal   bool  AddNewSpace( long  spaceSize)
        {
           
return  store.IncreaseQuotaTo(spaceSize);
        }
        
///   <summary>
        
///  得到独立存储区域里的目录
        
///   </summary>
        
///   <returns></returns>
         internal   string [] GetDirectoryNames()
        {
            
if  (store  !=   null )
            {
                
return  store.GetDirectoryNames();
            }
            
else
            {
                
return   new   string [] { "" };
            }
        }
        
///   <summary>
        
///  得到独立存储区域里的目录
        
///   </summary>
        
///   <param name="searchStr"> 可以使用?,*匹配符号 </param>
        
///   <returns></returns>
         internal   string [] GetDirectoryNames( string  searchStr)
        {
            
if  (store  !=   null )
            {
                
return  store.GetDirectoryNames(searchStr);
            }
            
else
            {
                
return   new   string [] {  ""  };
            }
        }
        
///   <summary>
        
///  检查文件夹是否存在
        
///   </summary>
        
///   <param name="directName"></param>
        
///   <returns></returns>
         internal   bool  DirectorExist( string  directName)
        {
            
return  store.DirectoryExists(directName);
          
        }
        
///   <summary>
        
///  判断文件是否存在
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <returns></returns>
         internal   bool  FileExist( string  filePath)
        {
            
return  store.FileExists(filePath);
        }
        
///   <summary>
        
///  获取独立存储区域里的所有文件名
        
///   </summary>
        
///   <returns></returns>
         internal   string [] GetFileNames()
        {
            
if  (store  !=   null )
            {
                
return  store.GetFileNames();
            }
            
else
            {
                
return   new   string [] {  ""  };
            }
        }
        
///   <summary>
        
///  在独立存储区域里新建目录
        
///   </summary>
        
///   <param name="DirectoryName"></param>
        
///   <returns></returns>
         internal   bool  CreateDirectory( string  DirectoryName)
        {
            
if  (store  !=   null )
            {
                store.CreateDirectory(DirectoryName);
                
return   true ;
            }
            
else
            {
                
return   false ;
            }
        }
        
///   <summary>
        
///  根据制定文件地址创建文件,如果路径不存在,则自动创建目录
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <returns></returns>
         internal  IsolatedStorageFileStream CreateFile( string  filePath)
        {
            
if  (store  !=   null )
            {
              filePath 
=   filePath.Replace( ' \\ ' , ' / ' );
                
// 设定文件夹只有两层,比如data/objects.zip
                 if  (filePath.Contains( " / " ))
                {
                    
string  diractory  =  filePath.Substring( 0 , filePath.IndexOf( " / " )); //  得到data
                     string  filename  =  filePath.Substring(filePath.LastIndexOf( " / " +   1 ); // 得到filename
                     if  ( ! DirectorExist(diractory))
                    {
                        CreateDirectory(diractory);
                    }
                }
               
return  store.CreateFile(filePath);
            }
            
else
            {
                
return   null ;
            }
        }
        
///   <summary>
        
///  把制定内容写入到指定文件中
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <param name="content"></param>
        
///   <returns></returns>
         internal   bool  WriteToFile( string  filePath, string  content)
        {
            
if  (store.FileExists(filePath))
            {
                
try
                {
                    
using  (StreamWriter sw  =
                        
new  StreamWriter(store.OpenFile(filePath,
                            FileMode.Open, FileAccess.Write)))
                    {
                        sw.WriteLine(content);
                        
return   true ;
                    }
                }
                
catch  (IsolatedStorageException ex)
                {
                    
return   false ;

                }
            }
            
else
            {
                
return   false ;
            }

        }
        
///   <summary>
        
///  把制定的流数据写入到指定数据中
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <param name="fs"></param>
        
///   <returns></returns>
         internal   bool  WriteToFile( string  filePath, Stream fs)
        {
            
if  (store.FileExists(filePath))
            {
                
try
                {
                    
using  (Stream sw  = store.OpenFile(filePath,
                            FileMode.Open, FileAccess.Write))
                    {
                        Byte[] data 
=   new   byte [fs.Length];
                        fs.Read(data, 
0 , ( int )fs.Length);
                        sw.Write(data, 
0 , ( int )fs.Length);
                        sw.Flush();
                        sw.Close();
                        
return   true ;
                    }
                }
                
catch  (IsolatedStorageException ex)
                {
                    
return   false ;
                }
            }
            
else
            {
                
return   false ;
            }
        }
        
///   <summary>
        
///  从指定文件中读取内容
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <returns></returns>
         internal   string  ReadContentFromFile( string  filePath)
        {
            
try
            {
                
using  (StreamReader reader  =
                    
new  StreamReader(store.OpenFile(filePath,
                        FileMode.Open, FileAccess.Read)))
                {
                    
string  contents  =  reader.ReadToEnd();
                    
return  contents;
                }
            }
            
catch  (IsolatedStorageException)
            {
                
return   "" ;
            }

        }
        
///   <summary>
        
///  读取指定文件的流
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <returns></returns>
         internal  Stream ReadStreamFromFile( string  filePath)
        {
           
return   store.OpenFile(filePath, FileMode.Open, FileAccess.Read);
        }
        
///   <summary>
        
///  删除指定的文件
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <returns></returns>
         internal   bool  DeleteFile( string  filePath)
        {
            
try
            {
                
if  (store.FileExists(filePath))
                {
                    store.DeleteFile(filePath);
                    
return   true ;
                }
                
else
                {
                    
return   false ;
                }
            }
            
catch  (IsolatedStorageException)
            {
                
return   false ;
            }

        }
        
///   <summary>
        
///  删除指定的目录
        
///   </summary>
        
///   <param name="dirDelete"></param>
        
///   <returns></returns>
         internal   bool  DeleteDirectory( string  dirDelete )
        {
            
try
            {
                
if  (store.DirectoryExists(dirDelete))
                {
                    store.DeleteDirectory(dirDelete);
                    
return   true ;
                }
                
else
                {
                    
return   false ;
                }
            }
            
catch  (IsolatedStorageException ex)
            {
                
return   false ;
            }
        }

        
#endregion
    }

 

 

        IsolatedStorageUtil类里的代码很简单,但在后面却非常频繁的使用到。写完了IsolatedStorageUtil类,大家就会问了,那服务端的文件如何如何下载到客户端呢?xap包是自动下载到内存,可是现在我们的资源没有放到xap包里,怎么办?

        还是那句话,看微软的官方文档。什么?你说你从来没看过文档,那真可惜了,作为一个.net程序员,“红宝书”般的东西,不说倒背如流,遇到问题的时候翻翻,总能让你茅塞顿开。

        我当时在群里大喊:“兄弟们,如果下载文件包到本地啊?”喊了几声,没人回答我。那时候我们群里用silverlight写比较大点的游戏的就5个人,深蓝,我,潮州人,开心银光,上海goods。深蓝写了非常有名的系列文章,潮州人写了SNS社区的游戏,开心银光写了“冒险岛”,上海goods写的就杂了:德州扑克,把深蓝的游戏改成网络版,我呢,就一门心思想把“传奇”搬到web上来。

        没人回答我,是因为大家都是才跟随“深蓝”的脚步,踏入silverlight游戏开发的不毛之地,大家都是摸着石头过河,只能靠自己摸索了。

        我见没人解答我的问题,想起“红宝书”,忙翻开一看,在“网络和通讯”章节里有一篇叫“按需下载”,这一定是我要的。我现在做的东西不就是“按需下载”么?

        原来,从silverlight2后webclient取代了Downloader 地位,专门负责silverlight客户端的网络下载。文档里写的清清楚楚,明明白白,真是“众里寻他千百度,蓦然回首,却在灯火阑珊处。”

        大家可以打开MSDN里的文章看看,不是“红宝书”是什么?

         看完“红宝书”,我赶忙写出了DownloadHelper类,在这里我有个疑问,我想写一个批量下载多个文件的方法,效果却不是太好,连续下载的文件一多,文件的保存就有问题,有的文件保存失败,如果有谁能改进下这个类里的DownloadFilesByWhile()方法,不盛感激,现在我只用这个方法下载单个文件。

         写完后,在测试过程收获还不小,如下:

ExpandedBlockStart.gif
  1.文件下载用webclient受服务器配置文件的限制,只能下载200M以内的,能不能下载还要受策略文件的影响。

   2.webclient异步下载返回的e.resault 转化成stream可以,不能强行转化为filestream

   3.把下载完成后的e.resault转化成stream后作保存操作时,结束的时候流不能关闭,和我们通常的操作不一样,所以这就是为什么我第一个文件能保存,后面不能保存的原因了。我猜测是这个流处于缓冲区里,关闭的话会清空缓冲区,导致后面下载的文件流也被清空。

   4.开单独线程下载,和界面线程通讯的话要用线程间通讯的post,或者get方法

   5.多文件下载要用循环,但是文件什么时候下载完是不确定的,又是异步的,所以要把下载线程阻止,在一个文件被下载完之前,当文件下载完毕后在解除阻止,进行循环的下一步。

       DownloadHelper类:

ExpandedBlockStart.gif DownloadHelper
  ///   <summary>
    
///  资源下载类,使用webclient, by williams
    
///   </summary>
     internal   class  DownloadHelper:IDisposable
    {
        
#region  私有成员
        IsolatedStorageUtil isu;
        
private  WebClient client;
        IGameCmd downloadEvent;
        
private  SynchronizationContext ui;
        
private   bool  isThreadSingle = true ;
        System.Threading.Thread t;
        
private  ManualResetEvent downloadDone  =   new  ManualResetEvent( false );
        
private  String[] filePaths;
        
private   bool  isDownLoadIng = false ;
        
private  DownLoadTypeEnum type  =  DownLoadTypeEnum.Map;
        
#endregion

        
internal  DownloadHelper(IGameCmd up)
        {
            isu 
=   new  IsolatedStorageUtil();
            client 
=   new  WebClient();
            client.AllowReadStreamBuffering 
=   true ;
            ui 
=  System.Threading.SynchronizationContext.Current;
            downloadEvent 
=  up;
        }
        
///   <summary>
        
///  批量异步下载多个文件,效果需要验证
        
///   </summary>
        
///   <param name="filepaths"></param>
         internal   void  DownloadMultiFile(String[] filepaths,DownLoadTypeEnum type)
        {
            filePaths 
=  filepaths;
            t 
=   new  Thread(DownloadFilesByWhile);
            t.IsBackground 
=   true ;
            t.Start();
            isThreadSingle 
=   false ;
            
this .type  =  type;
        }
        
private   void  DownloadFilesByWhile()
        {
            
foreach  ( string  filePath  in  filePaths)
            {
                
if  (isu.FileExist(filePath))
                {
                    
continue ;
                }
                
if  ( ! client.IsBusy)
                {
                    
                    downloadDone.Reset();
                    client.DownloadProgressChanged 
+=   new  DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
                    client.OpenReadCompleted 
+=   new  OpenReadCompletedEventHandler(client_OpenReadCompleted);
                    client.OpenReadAsync(
new  Uri(filePath, UriKind.Relative), filePath);
                    downloadDone.WaitOne();
                }
               
            }
         
            
byte  type  = Convert.ToByte(GameCmdEnums.GetFileOk);
            
byte  flag  =  Convert.ToByte( this .type);
            
byte [] content  =  System.Text.UTF8Encoding.UTF8.GetBytes( " 文件全部获取完毕 " );
           ui.Post(downloadEvent.DownloadFilesComplete, 
new  Message { Class = type, Flag = flag, Content = content, Size = content.Length });
        }
        
///   <summary>
        
///  下载指定文件
        
///   </summary>
        
///   <param name="filePath"></param>
        
///   <returns></returns>
         internal   bool  DownloadFile( string  filePath)
        {
            
if  ( ! string .IsNullOrEmpty(filePath))
            {
                    
if  ( ! client.IsBusy)
                    {
                        client.DownloadProgressChanged 
+=   new  DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
                        client.OpenReadCompleted 
+=   new  OpenReadCompletedEventHandler(client_OpenReadCompleted); 
                        client.OpenReadAsync(
new  Uri(filePath, UriKind.Relative), filePath);
                        
return   true ;
                    }
                    
else
                    {
                        
return   false ;
                    }
            }
            
else
            {
                
return   false ;
            }
        }
        
///   <summary>
        
///  下载进度发生变化时
        
///   </summary>
        
///   <param name="sender"></param>
        
///   <param name="e"></param>
         void  client_DownloadProgressChanged( object  sender, DownloadProgressChangedEventArgs e)
        {
                
string  mess  =   " 下载: "   +  e.UserState.ToString()  +   " 中...  "   +  e.ProgressPercentage.ToString()  +   " % " ;
                
if  (e.ProgressPercentage  ==   100 )
                {
                    mess 
=   " 下载: "   +  e.UserState.ToString()  +   " 完成 " ;
                }
                ui.Post(downloadEvent.DownloadProgressChange, mess);
        }

      
///   <summary>
      
///  文件下载完成后,储存进独立存储区域
      
///   </summary>
      
///   <param name="sender"></param>
      
///   <param name="e"></param>
         void  client_OpenReadCompleted( object  sender, OpenReadCompletedEventArgs e)
        {
            Stream fs 
=  e.Result  as  Stream;
            
if  (fs  !=   null )
            {
                
long  filezise  =  fs.Length;
             
                ui.Post(downloadEvent.DownloadComplete, e);
                
if  (filezise  <  isu.availableFreeSpace) // 独立存储区域的初始大小是1M
                {
                    SaveInIsolatedSpace(fs, e.UserState.ToString());
                }
                
else
                {
                    ui.Post(
this .downloadEvent.DownloadError,  " 存储空间不够 " );
                }
            }
            
else
            {
                ui.Post(
this .downloadEvent.DownloadError,  " 文件读取失败 " );
            }
            
if  ( ! isThreadSingle)
            {
                downloadDone.Set();
            }
          
        }
        
///   <summary>
        
///  把文件存入独立储存区里
        
///   </summary>
        
///   <param name="fs"></param>
        
///   <param name="filename"></param>
         void  SaveInIsolatedSpace(Stream fs,  string  filename)
        {
            
try
            {
                
if  ( ! isu.FileExist(filename))
                {
                    Stream newfs 
=  isu.CreateFile(filename); // 事先把地图文件名存储在 e 里。
                    newfs.Close();
                }
                isu.WriteToFile(filename, fs);
          
            }
             
catch (IsolatedStorageException ex)
            {
              
                 ui.Post(downloadEvent.DownloadError,
" 文件保存失败 " );
            }
            
catch  
            {
                ui.Post(downloadEvent.DownloadError, 
" 文件保存失败 " );
            }
           
        }

        
#region  IDisposable 成员

        
public   void  Dispose()
        {
            
if  (t  !=   null )
            {
                t.Abort();
            }
        }

        
#endregion

 

       在游戏里的运行效果如图:

      

                                      

 

         不过让我不爽的是:微软为了安全的原因,增加独立存储区域的时候,非要用户点下确定按钮,这样给用户体验不太好,为什么不能向flash game那样,直接就下载下来呢?

                               

                  

 

          还有一个让我也不爽的是:从独立存储区域存放的zip文件里读取资源的时候,明显感觉速度慢,导致游戏人物播放帧动画的时候很卡,我只好在游戏开始前把资源预先加载到内存里。这个问题群里的nowpaper也说读取速度慢。

           基于以上两点,我觉得这让独立存储区域成了有点“鸡肋”般东西,如果微软能改进下,那么用silverlight开发大型MMorpg游戏还是不错的选择。

           IsolatedStorage,想说爱你不容易!

       

转载于:https://www.cnblogs.com/wangergo/archive/2010/05/26/1744729.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值