当前位置: 首页 > article >正文

适用于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
    {
        
    }
}


http://www.kler.cn/news/315001.html

相关文章:

  • react的事件绑定
  • vulnhub(12):bob 1.0.1(gpg文件解密)
  • @PostConstruct
  • <刷题笔记> 力扣236题——二叉树的公共祖先
  • 全面详尽的 PHP 环境搭建教程
  • C++ 元编程
  • 18938 汉诺塔问题
  • 《深度学习》PyTorch 常用损失函数原理、用法解析
  • 【电力系统】基于遗传算法的33节点电力系统无功优化及MATLAB实现
  • LeetCode337. 打家劫舍III
  • springbootKPL比赛网上售票系统
  • Maven 项目无法下载某个依赖
  • 论 JAVA 集合框架中 接口与类的关系
  • 注册信息安全专业人员(CISP)和网络安全的联系与区别
  • FLStudio21Mac版flstudio v21.2.1.3430简体中文版下载(含Win/Mac)
  • windows cuda12.1 pytorch gpu环境配置
  • js之遍历方法
  • windows@文件系统链接@快捷方式@快捷键方式和符号链接及其对比
  • 本地提权【笔记总结】
  • 《AI:开启未来的无限可能》
  • 【django】局域网访问django启动的项目
  • MongoDB解说
  • 机器人速度雅可比矩阵(机器人动力学)
  • 自动化立体仓库与堆垛机单元的技术参数
  • 设计模式之结构型模式例题
  • 简单题35-搜索插入位置(Java and Python)20240919
  • 如何使用 C# 解决 Cloudflare Turnstile CAPTCHA 挑战
  • Flyway 基本概念
  • 零停机部署的“秘密武器”:为什么 Kamal Proxy 能成为你架构中的不二之选?
  • 面试金典题2.2