自学内容网 自学内容网

适用于QF的存档系统

存档系统

今天分享一个适用于QF的存档系统

这个系统的优点为

1、轻量化,总共代码不超过400行

2、自动化,基于QF框架,自动注入值

缺点:

1、不能序列化Unity内部类型,如Vector

2、需要给能被序列化的类加上【Serialize】属性

依赖下载

在Unity的包管理器中,输入Newtonsoft.json,下载依赖

模块分析

Storage:工具模块

维护一个数据缓冲区,负责将数据从磁盘中读取到缓冲区中,并且从缓冲区获取数据写入磁盘

using QFramework;

namespace EggFramework.Storage
{
    public interface IStorage : IUtility
    {
        void AssignSavePath(string path = "saveData");
        void ReadFromDisk();
        void WriteToDisk();
        T Load<T>(string key, T defaultValue,out bool newValue);
        void Save<T>(string key, T saveData);
        void Clear();
    }
}

接口模块定义如上

FileSystem:系统模块

维护一个保存了存档名的列表,并且负责实际注册数据,加载数据,保存数据

using QFramework;
using System.Collections.Generic;

namespace EggFramework.FileSystem
{
    public interface IFileSystem : ISystem
    {
        List<string> FileNames { get; }
        void Register<T>(BsProperty<T> savable, string name);
        void Unregister<T>(BsProperty<T> savable);
        void CreateFile(string fileName);
        //自动加载当前的存档
        void LoadFile(string fileName = "File1");
        void SaveFile();
        void DeleteFile(string fileName);
        void DeleteAll();
    }
}

其中BSProperty定义如下

#region

//文件创建者:Egg
//创建时间:09-10 02:24

#endregion

using System;
using QFramework;

namespace EggFramework.FileSystem
{
    public sealed class BsProperty<T> : BindableProperty<T>, ISavable
    {
        Action ISavable.OnLoad { get; set; } = () => { };
        Action ISavable.OnSave { get; set; } = () => { };
    }
}
#region

//文件创建者:Egg
//创建时间:09-10 02:23

#endregion

using System;

namespace EggFramework.FileSystem
{
    public interface ISavable
    {
        Action OnLoad { get; set; }
        Action OnSave { get; set; }
    }
}

通过ISavable限制BSProperty,并且通过在框架初始化的时候,将数据注册到FileSystem,加载时,统一将数据注入BSProperty。

Storage实现

using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using UnityEngine;

namespace EggFramework.Storage
{
    public sealed class JsonStorage : IStorage
    {
        private string _savePath = "saveData.json";

        private Dictionary<string, object> _saveData = new();

        public void ReadFromDisk()
        {
            var path = Path.Combine(Application.persistentDataPath, _savePath);
            Debug.Log(path);
            if (File.Exists(path))
            {
                var json = File.ReadAllText(Path.Combine(Application.persistentDataPath, _savePath));

                _saveData = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
                Debug.Log("读取成功");
            }
            else
            {
                _saveData.Clear();
            }
        }

        public void WriteToDisk()
        {
            var json = JsonConvert.SerializeObject(_saveData);

            File.WriteAllText(Path.Combine(Application.persistentDataPath, _savePath), json);
        }

        public void Save<T>(string key, T saveData)
        {
            if (saveData == null)
            {
                Debug.LogWarning("Saving null data");
            }

            if (_saveData.TryAdd(key, saveData))
            {
                _saveData[key] = saveData;
            }
        }

        public T Load<T>(string key, T defaultValue, out bool newValue)
        {
            newValue = false;

            if (!_saveData.TryGetValue(key, out var saveValue))
            {
                newValue = true;
                return defaultValue;
            }

            //5月15日补丁,对直接使用的布尔类型区别处理
            if (typeof(T) == typeof(bool))
            {
                return (T)saveValue;
            }

            return JsonConvert.DeserializeObject<T>(saveValue.ToString());
        }

        public void AssignSavePath(string path = "saveData")
        {
            _savePath = path + ".json";
        }

        public void Clear()
        {
            _saveData.Clear();
        }
    }
}

FileSystem实现

using QFramework;
using System.Collections.Generic;
using EggFramework.Storage;
using UnityEngine;

namespace EggFramework.FileSystem
{
    public sealed class FileSystem : AbstractModule, IFileSystem
    {
        public List<string> FileNames { get; private set; } = new();

        private bool _inited;

        private bool _loaded;

        private IStorage _storage;
        private readonly List<ISavable> _savableProperties = new();
        private readonly Dictionary<ISavable, object> _defaultValues = new();
        private string _currentFile = string.Empty;

        public void DeleteFile(string fileName)
        {
            MakeSureInited();
            if (FileNames.Contains(fileName))
            {
                _storage.AssignSavePath(fileName);
                _storage.Clear();
                _storage.WriteToDisk();
                FileNames.Remove(fileName);
                Debug.Log("删除成功");
            }
            else
            {
                Debug.Log("要删除的存档不存在");
            }
        }

        public void DeleteAll()
        {
            MakeSureInited();
            foreach (var fileName in FileNames)
            {
                DeleteFile(fileName);
            }
        }

        private void MakeSureInited()
        {
            if (string.IsNullOrEmpty(_currentFile))
            {
                if (FileNames == null)
                {
                    OnInit();
                }

                if (FileNames!.Count == 0)
                {
                    FileNames.Add("File1");
                }

                _currentFile = FileNames[0];
            }
        }

        private T Load<T>(string key, T defaultValue, out bool isNew)
        {
            MakeSureInited();
            return _storage.Load(key, defaultValue, out isNew);
        }

        private void LoadFileInner()
        {
            MakeSureInited();
            SaveFileName();
            //清除缓存区
            _storage.Clear();
            //指定路径
            _storage.AssignSavePath(_currentFile);
            //加载数据
            _storage.ReadFromDisk();
            //为每个已注册值赋值
            foreach (var savable in _savableProperties)
            {
                savable.OnLoad?.Invoke();
            }

            _loaded = true;
        }

        //必須在所有值都註冊完畢後,调用LoadFile,否则无法填充对应的值
        public void LoadFile(string fileName = "File1")
        {
            _currentFile = fileName;
            
            LoadFileInner();
        }

        /// <summary>
        ///用于将存档名写入文件
        /// 
        /// </summary>
        private void SaveFileName()
        {
            MakeSureInited();
            //指定路径
            _storage.AssignSavePath();
            //读取磁盘
            _storage.ReadFromDisk();
            //写入缓存区
            _storage.Save(nameof(FileNames), FileNames);
            //写入磁盘
            _storage.WriteToDisk();
        }

        private void Save<T>(string key, T value)
        {
            MakeSureInited();
            _storage.Save(key, value);
        }

        public void SaveFile()
        {
            if (!_loaded)
            {
                Debug.LogWarning("需要先加载一个存档才行");
                return;
            }
            _storage.AssignSavePath(_currentFile);
            
            _storage.Clear();
            //依次调用onSave方法,把注册数据写入缓存区
            foreach (var savable in _savableProperties)
            {
                savable.OnSave?.Invoke();
            }
            //将缓存区中的数据写入文件
            _storage.WriteToDisk();
            //将存档名写入文件
            SaveFileName();
        }

        protected override void OnInit()
        {
            if (!_inited)
            {
                _storage = this.GetUtility<IStorage>();
                _storage.AssignSavePath();
                FileNames = _storage.Load(nameof(FileNames), new List<string>(), out _);
                _inited = true;
            }
        }

        //CreateFile有两个重载
        //可以自定义存档名或者默认存档名
        public void CreateFile(string fileName)
        {
            MakeSureInited();
            
            if (!FileNames.Contains(fileName))
            {
                FileNames.Add("File" + fileName);
                SaveFileName();
            }
        }

        public void Register<T>(BsProperty<T> savable, string name)
        {
            if (!_savableProperties.Contains(savable))
            {
                _savableProperties.Add(savable);
                _defaultValues.Add(savable, savable.Value);
                var saveItem = (ISavable)savable;
                saveItem.OnLoad += () =>
                {
                    var value = Load(name, (T)_defaultValues[savable], out var isNew);
                    if (!isNew)
                        savable.Value = value;
                    else
                        savable.Value = (T)_defaultValues[savable];
                };
                saveItem.OnSave += () => Save(name, savable.Value);
            }
            else Debug.Log("重复注册值");
        }

        public void Unregister<T>(BsProperty<T> savable)
        {
            if (_savableProperties.Contains(savable))
            {
                _savableProperties.Remove(savable);
                var saveItem = (ISavable)savable;
                saveItem.OnLoad = null;
                saveItem.OnSave = null;
            }
            else Debug.Log("重复注销值");
        }
    }
}
#region

//文件创建者:Egg
//创建时间:09-11 07:30

#endregion


using QFramework;

namespace EggFramework
{
    public abstract class AbstractModule : AbstractSystem
    {
        
    }
}


原文地址:https://blog.csdn.net/2301_80005044/article/details/142377987

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!