Unity本地數據存儲---Sqlite和JSON

 

2014-05-04更新html

SqliteDatabase.cs這個文件的初始方法有問題,具體是若是指定URL已經存在了DB文件,就不會從新覆蓋DB文件。android

這致使咱們修改以後的DB文件沒法產生效果。ios

本人的解決辦法是在遊戲啓動的界面,經過對比本地的Resources目錄下的文件A,和玩家核心數據B裏面的數據庫版本號,sql

若是A>B,則斷定本地的DB文件版本較老,須要更新。數據庫

具體代碼請到目錄SQLite篇下下載c#

 

 

2014-04-30更新網絡

剔除了使用網絡上爛大街的SQLite使用方法(緣由android下沒法讀取數據),使用libSQLite3.so,經過DLLImport,在C#代碼裏直接調用C接口數據結構

這種原生調用SQLite的方式,我在pc、android上親測無誤,ios沒測過,可是stackoverflow上有兄弟試過,沒問題。園子的朋友若是能夠測IOS的,歡迎提供結果app

 

基本思路,遊戲基礎配置數據,好比怪物的屬性、裝備模板屬性、關卡怪物等,使用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 ("取消");
    }  
}
相關文章
相關標籤/搜索