首页 前端知识 Unity进阶,Unity存档系统(Json可序列化存档,AES加密)

Unity进阶,Unity存档系统(Json可序列化存档,AES加密)

2024-06-07 12:06:13 前端知识 前端哥 676 868 我要收藏

存档系统

1.JSON讲解

关于JSON的具体描述可以百度

2.JsonUtility

JsonUtility可以将可序列对象转化为Json格式的文件,那么,使用JsonUtility搭建存档系统的核心思路就是

    第一步,将需要保存的数据转化位Json格式

    第二步,将转换后Json文件写在某个路径下的一个文件夹中

当然读取的时候反过来就可以了

我们知道Json有一个优点,那就是直观易读,但是在存档系统中,Json的这个有点将成为致命的缺点,那就是其他人也是易读的,这样就会造成一种结果,那就是存档后,将存档文件修改,就可以做到开G

所以,为了避免这种情况,我们将使用AES进行加密,其他的加密方式也可以,具体看自己需求

下面开始存档系统的搭建

3.第一步存档

写一个函数,需要传递两个参数,一个是保存的存档文件的文件名,另一个是需要存档的数据文件,为object类型

第一步便是json转换

第二步是AES加密(该函数待会儿写)

第三步确定保存的路径

var path = Path.Combine(Application.persistentDataPath, saveFileName);

这行代码Path.Combine()用于将传入的两个参数结合

Application.persistentDataPath 是Unity提供的API,自动获取路径,详见Unity手册

saveFileName 是保存的文件名字

接下来便使用try catch语句来进行异常的捕获

public static void SaveByJson(string saveFileName, object data)
        {
            var json = JsonUtility.ToJson(data);
            var encryptedJson = EncryptString(key, json);  // AES解密
            var path = Path.Combine(Application.persistentDataPath, saveFileName);

            try
            {
                File.WriteAllText(path, encryptedJson);
                #if UNITY_EDITOR
                Debug.Log($"成功保存到 {path}.");
                #endif
            }
            catch(System.Exception exception)
            {
                #if UNITY_EDITOR
                Debug.Log($"文件保存到 {path}. \n{exception}");
                #endif
            }
        }

 4.读取存档

具体不多讲,看代码

public static T LoadFromJson<T>(string saveFileName)
        {
            var path = Path.Combine(Application.persistentDataPath, saveFileName);

            try
            {
                //var json = File.ReadAllText(path);
                var encryptedJson = File.ReadAllText(path);
                var json = DecryptString(key, encryptedJson);// 使用解密函数解密数据
                var data = JsonUtility.FromJson<T>(json);
                Debug.Log($"成功读取到 {path}.");

                return data;
            }
            catch(System.Exception exception)
            {
                #if UNITY_EDITOR
                Debug.Log($"文件从 {path} 加载. \n{exception}");
                #endif

                return default;
            }
        }

 5.删除存档

public static void DeleteSaveFile(string saveFileName)
        {
            var path = Path.Combine(Application.persistentDataPath, saveFileName);

            try
            {
                File.Delete(path);
                Debug.Log($"成功删除到 {path}.");

            }
            catch(System.Exception exception)
            {
                #if UNITY_EDITOR
                Debug.Log($"文件从 {path} 删除. \n{exception}");
                #endif

            }
        }

6.AES加解密(采用16位key进行加解密)

/// <summary>
        /// AES加密函数
        /// </summary>
        /// <param name="key"></param>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string EncryptString(string key, string plainText)
        {
            byte[] iv = new byte[16];
            byte[] array;

            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
                        {
                            streamWriter.Write(plainText);
                        }
                        array = memoryStream.ToArray();
                    }
                }
            }

            return Convert.ToBase64String(array);
        }

        /// <summary>
        /// AES解密函数
        /// </summary>
        /// <param name="key"></param>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static string DecryptString(string key, string cipherText)
        {
            byte[] iv = new byte[16];
            byte[] buffer = Convert.FromBase64String(cipherText);

            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

                using (MemoryStream memoryStream = new MemoryStream(buffer))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader streamReader = new StreamReader(cryptoStream))
                        {
                            return streamReader.ReadToEnd();
                        }
                    }
                }
            }
        }

7.Python随机生成AES的key

 

from Crypto.Random import get_random_bytes

def generate_aes_key(key_length=16):
    """
    生成指定长度的 AES 密钥

    参数:
    key_length: int,密钥长度,默认为 16 字节

    返回值:
    bytes,生成的 AES 密钥
    """
    if key_length not in [16, 24, 32]:
        raise ValueError("AES密钥长度必须是16、24或32字节")
    return get_random_bytes(key_length)

# 生成一个16字节(128位)的 AES 密钥
aes_key = generate_aes_key()
print("生成的AES密钥:", aes_key.hex())

 8.整体代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

namespace FilingSystem
{
    /// <summary>
    /// 存档系统
    /// </summary>
    public static class SaveSystem
    {
        private static string key = "b244a02444908deb248a0792ad540d25";
        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="saveFileName">文件名,保存数据的文件名</param>
        /// <param name="data">需要保存的数据</param>
        public static void SaveByJson(string saveFileName, object data)
        {
            var json = JsonUtility.ToJson(data);
            var encryptedJson = EncryptString(key, json);  // AES解密
            var path = Path.Combine(Application.persistentDataPath, saveFileName);

            try
            {
                File.WriteAllText(path, encryptedJson);
                #if UNITY_EDITOR
                Debug.Log($"成功保存到 {path}.");
                #endif
            }
            catch(System.Exception exception)
            {
                #if UNITY_EDITOR
                Debug.Log($"文件保存到 {path}. \n{exception}");
                #endif
            }
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="saveFileName">读取数据的文件名</param>
        /// <typeparam name="T">泛型</typeparam>
        /// <returns></returns>
        public static T LoadFromJson<T>(string saveFileName)
        {
            var path = Path.Combine(Application.persistentDataPath, saveFileName);

            try
            {
                //var json = File.ReadAllText(path);
                var encryptedJson = File.ReadAllText(path);
                var json = DecryptString(key, encryptedJson);// 使用解密函数解密数据
                var data = JsonUtility.FromJson<T>(json);
                Debug.Log($"成功读取到 {path}.");

                return data;
            }
            catch(System.Exception exception)
            {
                #if UNITY_EDITOR
                Debug.Log($"文件从 {path} 加载. \n{exception}");
                #endif

                return default;
            }
        }

        /// <summary>
        /// 删除存档
        /// </summary>
        /// <param name="saveFileName"></param>
        public static void DeleteSaveFile(string saveFileName)
        {
            var path = Path.Combine(Application.persistentDataPath, saveFileName);

            try
            {
                File.Delete(path);
                Debug.Log($"成功删除到 {path}.");

            }
            catch(System.Exception exception)
            {
                #if UNITY_EDITOR
                Debug.Log($"文件从 {path} 删除. \n{exception}");
                #endif

            }
        }
        /// <summary>
        /// AES加密函数
        /// </summary>
        /// <param name="key"></param>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string EncryptString(string key, string plainText)
        {
            byte[] iv = new byte[16];
            byte[] array;

            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
                        {
                            streamWriter.Write(plainText);
                        }
                        array = memoryStream.ToArray();
                    }
                }
            }

            return Convert.ToBase64String(array);
        }

        /// <summary>
        /// AES解密函数
        /// </summary>
        /// <param name="key"></param>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static string DecryptString(string key, string cipherText)
        {
            byte[] iv = new byte[16];
            byte[] buffer = Convert.FromBase64String(cipherText);

            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

                using (MemoryStream memoryStream = new MemoryStream(buffer))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader streamReader = new StreamReader(cryptoStream))
                        {
                            return streamReader.ReadToEnd();
                        }
                    }
                }
            }
        }

    }   
}

 9.测试代码

注意playerName的赋值,存档前和存档后playerName的值要一致

using System.Collections;
using System.Collections.Generic;
using FilingSystem;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class SaveSystemTest : MonoBehaviour
{
    [SerializeField] private string playerName;
    [SerializeField] private float score;
    [SerializeField] private Vector3 vector;
    [SerializeField] private Button saveButton;
    [SerializeField] private Button loadButton;
    [SerializeField] private Button deleteButton;
    [SerializeField] private TMP_Text scoreText;
    [SerializeField] private TMP_Text transformText;
    const string PLAYER_SAVE_FILENAME = "JackieText";

    [System.Serializable]class PlayerData
    {
        public string playerName;         //玩家名字
        public float playerScore;         //玩家得分
        public Vector3 playerTransfrom;   //玩家位置
    }
    private void Start()
    {
        saveButton.onClick.AddListener(SaveButton);
        loadButton.onClick.AddListener(LoadButton);
        deleteButton.onClick.AddListener(DeleteButton);
    }

    //
    private void SaveButton()
    {
        PlayerData playerData = new PlayerData();
        playerData.playerName = playerName;
        playerData.playerScore = score;
        playerData.playerTransfrom = vector;
        SaveSystem.SaveByJson(PLAYER_SAVE_FILENAME+playerName, playerData);
    }
    private void LoadButton()
    {
        var saveData = SaveSystem.LoadFromJson<PlayerData>(PLAYER_SAVE_FILENAME+playerName);
        scoreText.text = saveData.playerScore.ToString();
        transformText.text = saveData.playerTransfrom.ToString();
    }
    private void DeleteButton()
    {
        SaveSystem.DeleteSaveFile(PLAYER_SAVE_FILENAME);
    }
}

转载请注明出处或者链接地址:https://www.qianduange.cn//article/11302.html
评论
发布的文章

echarts 鼠标划过显示信息

2024-06-14 23:06:40

echarts@5 动画失效

2024-06-14 23:06:39

vue3 聊天机器人 聊天界面

2024-06-14 23:06:06

Vue - Vue3 集成编辑器功能

2024-06-14 23:06:54

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!