zoukankan      html  css  js  c++  java
  • 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文档,我写了一个独立存储区域资源读写类

    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()方法,不盛感激,现在我只用这个方法下载单个文件。

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

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

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

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

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

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

           DownloadHelper类:

    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,想说爱你不容易!

           

  • 相关阅读:
    DES 加密算法
    socket编程之bind()函数
    如何启动ubuntu下的telnet服务
    基于duilib修改的版本上传了
    mmsPlayer, for android ,wince,windows,wm等
    [转]log4c 配置文件的用法
    mmsPlayer, for android ,wince,windows,wm等
    wince 版本的播放器 是基于 TC89系列
    cocos2dx做的一个圣诞节软件
    基于duilib修改的版本上传了
  • 原文地址:https://www.cnblogs.com/wangergo/p/1744729.html
Copyright © 2011-2022 走看看