适用于QF的存档系统

server/2024/9/23 3:23:54/

存档系统

今天分享一个适用于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#endregionusing 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#endregionusing 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;elsesavable.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#endregionusing QFramework;namespace EggFramework
{public abstract class AbstractModule : AbstractSystem{}
}


http://www.ppmy.cn/server/120601.html

相关文章

k8s环境搭建(续)

查看节点信息并做快照 kubectl get nodes 将components.yml文件上传到master主机 创建nginx&#xff0c;会在添加一个新的pod kubectl run nginx --imagesnginx:latest 查看nginx的pod信息 [rootk8s-master ~]# kubectl get po -Aowide|grep nginx 出现错误&#xff0c;查…

MyBatis 源码解析:ResultHandler 设计与应用

摘要 MyBatis 中的 ResultHandler 接口允许开发者在 SQL 查询过程中自定义结果集的处理方式&#xff0c;避免将所有结果加载到内存中。它在处理大量数据或特定业务逻辑时非常实用。本文将深入解析 MyBatis 中 ResultHandler 的工作原理&#xff0c;并通过自定义实现 ResultHan…

有理数四则运算

实验内容 &#xff08;1&#xff09;实现两个有理数相加、相减、相乘的运算。 &#xff08;2&#xff09;选作内容&#xff1a;实现两个有理数相除的运算 假设用户输入的分母总是非零的 首先定义了一个Rational结构体来存储有理数的分子&#xff08;numerator&#xff09;和…

数据集-目标检测系列-火车检测数据集 train >> DataBall

数据集-目标检测系列-火车检测数据集 train >> DataBall 数据集-目标检测系列-火车检测数据集 数据量&#xff1a;1W 想要进一步了解&#xff0c;请联系 DataBall。 DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;不断增加…

【系统架构设计师】软件架构的风格(经典习题)

更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1题】【第2题】【第3~4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15~16题】【第17题】【第18~19题】【第20~21题】【第22题】【第23题】【第24~…

OpenCore Legacy Patcher 2.0.0 发布,83 款不受支持的 Mac 机型将能运行最新的 macOS Sequoia

在不受支持的 Mac 上安装 macOS Sequoia (OpenCore Legacy Patcher v2.0.0) Install macOS on unsupported Macs 请访问原文链接&#xff1a;https://sysin.org/blog/install-macos-on-unsupported-mac/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主…

【hot100-java】【每日温度】

R8-栈篇 印象题:单调栈的使用 参考本人博客&#xff1a;单调栈 class Solution {public int[] dailyTemperatures(int[] temperatures) {int numtemperatures.length;int [] retnew int[num];Stack<Integer>stnew Stack<>();for (int i0;i<num;i){while(!st.…

JVM运行区域介绍

JVM运行区域是Java程序执行的核心支撑&#xff0c;它们共同保障了程序的正确执行、高效运行、并发支持、跨平台性以及安全性。现为大家深入解析JVM运行区域的工作原理和重要性。 一、JVM运行区介绍 JVM&#xff08;Java虚拟机&#xff09;在运行时会将内存空间划分为几个不同…