zoukankan      html  css  js  c++  java
  • Unity本地数据存储---Sqlite和JSON

    2014-05-04更新

    SqliteDatabase.cs这个文件的初始方法有问题,具体是如果指定URL已经存在了DB文件,就不会重新覆盖DB文件。

    这导致我们修改之后的DB文件无法产生效果。

    本人的解决办法是在游戏启动的界面,通过对比本地的Resources目录下的文件A,和玩家核心数据B里面的数据库版本号,

    如果A>B,则判定本地的DB文件版本较老,需要更新。

    具体代码请到目录SQLite篇下下载

    2014-04-30更新

    剔除了使用网络上烂大街的SQLite使用方法(原因android下无法读取数据),使用libSQLite3.so,通过DLLImport,在C#代码里直接调用C接口

    这种原生调用SQLite的方式,我在pc、android上亲测无误,ios没测过,但是stackoverflow上有兄弟试过,没问题。园子的朋友如果可以测IOS的,欢迎提供结果

    基本思路,游戏基础配置数据,比如怪物的属性、装备模板属性、关卡怪物等,使用SQLite(Unity插件SQLiteUnityKit-GitHub地址,推荐客户端SQLite Expert Personal 3),管理方便

    玩家核心数据(属性、装备、技能)使用JSON格式,加密保存在Application.persistentDataPath路径里,避免每次升级被覆盖

    插件本地下载地址

    Sqlite框架

    litJson

    准备工作

     1 litJson.dll放在Plugins目录下

     2 libsqlite3.so文件放到 Assets/Plugins/Android目录下

     3 自定义的SQLite DB数据文件放到 Assets/StreamingAssets目录下

    SQLite篇

     将准备好的DB数据文件拷贝到Assets/StreamingAssets

     把SQLiteUnityKit GitHub下载的压缩包里的 DataTable.cs、SqliteDatabase.cs,拷贝到项目中的任意位置

     最终项目结构看起来是这样子的

     SQLiteUnityKit框架用Dictionary数据结构模拟了DataTable,DataRow,因此我们执行查询语句的时候,返回的是DataTable,就像平时使用ado.net提供的查询模式一样。

     调用方式

    SqliteDatabase sqlDB = new SqliteDatabase(“config.db”);
    string query = “INSERT INTO User(UserName) VALUES( ‘Santiago’)”;
    sqlDB.ExecuteNonQuery(query);

    我做了个unitypackge的例子,大家可以下载导入

    Json篇

    原先是使用XML格式来存储数据的,因为XML跨平台,但是Json同样也可以做到,加上有LitJson这个格式转化利器,因此,本地文件存储格式,本文以Json为例。

    关于数据加密

    使用c#提供的加密类即可,自己定义秘钥

    using System.Security.Cryptography;
    using System.Text;
    
    public class GlobalDataHelper
    {
            private const string DATA_ENCRYPT_KEY = "a234857890654c3678d77234567890O2";
            private static RijndaelManaged _encryptAlgorithm = null;
    
            public static RijndaelManaged DataEncryptAlgorithm ()
            {
                    _encryptAlgorithm = new RijndaelManaged ();
                    _encryptAlgorithm.Key = Encoding.UTF8.GetBytes (DATA_ENCRYPT_KEY);
                    _encryptAlgorithm.Mode = CipherMode.ECB;
                    _encryptAlgorithm.Padding = PaddingMode.PKCS7;
    
                    return _encryptAlgorithm;
            }
    }

    关于破解版软件

    安卓机子上泛滥各种XXX破解版,关于破解版的问题,我们可以通过Unity提供的唯一机器ID,在写入玩家数据的时候,将其一并写入到数据中去,在读取数据之后,对比该ID和本机ID,如果不一致,则认为是破解版

    SystemInfo.deviceUniqueIdentifier

    本例子是以基础配置数据为例,因此代码中不提供该功能。

    关于避免更新之后,玩家存档被覆盖

    Unity提供了一个只读路径,放在该路径下的文件,不会被软件更新所影响。

    Application.persistentDataPath
    
    

    Json Helper类~~

    using System.Security.Cryptography;
    using System.Text;
    using System;
    using System.IO;
    using LitJson;
    
    public class DataStoreProcessor
    {
    
            private static DataStoreProcessor _dataStoreProcessor = null;
        
            public static DataStoreProcessor SharedInstance {
                    get {
                            if (_dataStoreProcessor == null)
                                    _dataStoreProcessor = new DataStoreProcessor ();
    
                            return _dataStoreProcessor;
                    }
            }
    
            /// <summary>
            /// 加密数据    
            /// </summary>
            /// <returns>The data.</returns>
            /// <param name="dataToEncrypt">Data to encrypt.</param>
            public string EncryptData (string dataToEncrypt)
            {
                    //给明文加密用GetBytes
                    byte[] dataToEncryptArray = Encoding.UTF8.GetBytes (dataToEncrypt);
                    byte[] dataAfterEncryptArray = GlobalDataHelper.DataEncryptAlgorithm().CreateEncryptor ()
                .TransformFinalBlock (dataToEncryptArray, 0, dataToEncryptArray.Length);
            
                    return Convert.ToBase64String (dataAfterEncryptArray, 0, dataAfterEncryptArray.Length);
            }
        
            /// <summary>
            /// 解密数据 
            /// </summary>
            /// <returns>The data.</returns>
            /// <param name="dataToDecrypt">Data to decrypt.</param>
            public string DecryptData (string dataToDecrypt)
            {
                    //给密文解密用FromBase64String
                    byte[] dataToDecryptArray = Convert.FromBase64String (dataToDecrypt);
                    byte[] dataAfterDecryptArray = GlobalDataHelper.DataEncryptAlgorithm().CreateDecryptor ()
                .TransformFinalBlock (dataToDecryptArray, 0, dataToDecryptArray.Length);
            
                    return Encoding.UTF8.GetString (dataAfterDecryptArray);
            }
    
            /// <summary>
            /// 数据保存
            /// </summary>
            /// <param name="tobject">Tobject.</param>
            /// <param name="path">Path.</param>
            /// <typeparam name="T">The 1st type parameter.</typeparam>
            public void Save (Object tobject, string path, bool isEncrypt=true)
            {
                    string serializedString = JsonMapper.ToJson (tobject);
    
                    using (StreamWriter sw = File.CreateText(path)) {
                            if (isEncrypt)
                                    sw.Write (EncryptData (serializedString));
                            else
                                    sw.Write (serializedString);
                    }
            }
    
            /// <summary>
            /// 载入数据
            /// </summary>
            /// <param name="path">Path.</param>
            /// <typeparam name="T">The 1st type parameter.</typeparam>
            public T Load<T> (string path, bool isEncrypt=true)
            {
                    if (File.Exists (path) == false)
                            return default(T);
            
                    using (StreamReader sr = File.OpenText(path)) {
                            string stringEncrypt = sr.ReadToEnd ();
                
                            if (string.IsNullOrEmpty (stringEncrypt))
                                    return default(T);
                
                            if (isEncrypt)
                                    return  JsonMapper.ToObject<T> (DecryptData (stringEncrypt));
                            else
                                    return JsonMapper.ToObject<T> (stringEncrypt);
                    }
            }
    }

    调用方式

     下面的代码将提供了一个自定义窗体,允许开发者自行定义用户在等待界面时,显示本地配置好的文字

     按照道理,这种游戏基础配置类的应该使用Sql方式来进行数据交互,本文仅仅是为了进行功能的演示。

    只有玩家数据,才使用本地文件存储的方式,存储在永久的路径里面

    using UnityEngine;
    using System.Collections.Generic;
    using UnityEditor;
    
    public class LoadingDataConfigWindow : ScriptableWizard
    {
        public List<string> NotifyString;
        //改成 Application.persistentDataPath永久存储
        private readonly string LOADING_DATA_CONFIG_URL = Application.dataPath + @"/Resources/Setting/LoadNotify.data";
    
    
        public LoadingDataConfigWindow()
        {
            NotifyString = DataStoreProcessor.SharedInstance.Load<List<string>>(LOADING_DATA_CONFIG_URL,false);
        }
    
        [MenuItem ("GameObject/Data Setting/Loading text")]
        static void CreateWizard ()
        {
            LoadingDataConfigWindow window =    DisplayWizard<LoadingDataConfigWindow> ("配置登陆提示文字", "确认", "取消");
            window.minSize = new Vector2(1024,768);
        }
        
        // This is called when the user clicks on the Create button.  
        void OnWizardCreate ()
        {  
            DataStoreProcessor.SharedInstance.Save(NotifyString,LOADING_DATA_CONFIG_URL,false);
            Debug.Log(string.Format(" 保存成功,共计录入 {0} 数据",NotifyString.Count));
        }  
        
        // Allows you to provide an action when the user clicks on the   
        // other button "Apply".  
        void OnWizardOtherButton ()
        {  
            Debug.Log ("取消");
        }  
    }
  • 相关阅读:
    Java 7如何操纵文件属性
    MS Server中varchar与nvarchar的区别
    【Unity3D】【NGUI】UICamera
    2007LA 3902 网络(树+贪心)
    读取图片的几种方式
    AssetsLibrary 实现访问相册,选取多张照片显示
    UIImagePickerController的用法
    画板的实现
    最近的状态
    富文本的使用-----实现图文混排 文字的检索 (正则表达式)
  • 原文地址:https://www.cnblogs.com/kimmy/p/3700565.html
Copyright © 2011-2022 走看看