Repository: wenen-creator/FlexiArchiveSystem Branch: dev Commit: a95d87ca13f4 Files: 205 Total size: 260.0 KB Directory structure: gitextract_mo7xdguh/ ├── .github/ │ └── FUNDING.yml ├── 3rdParty/ │ ├── Plugins/ │ │ ├── Android/ │ │ │ ├── libs/ │ │ │ │ ├── arm64-v8a/ │ │ │ │ │ └── libsqlite3.so.meta │ │ │ │ ├── arm64-v8a.meta │ │ │ │ ├── armeabi-v7a/ │ │ │ │ │ └── libsqlite3.so.meta │ │ │ │ ├── armeabi-v7a.meta │ │ │ │ ├── x86/ │ │ │ │ │ └── libsqlite3.so.meta │ │ │ │ └── x86.meta │ │ │ └── libs.meta │ │ ├── Android.meta │ │ ├── LitJson.dll.meta │ │ ├── Mono.Data.Sqlite.dll.meta │ │ ├── System.Data.dll.meta │ │ └── sqlite3.dll.meta │ └── Plugins.meta ├── 3rdParty.meta ├── Engine/ │ ├── Unity/ │ │ ├── Editor/ │ │ │ ├── EditorSetting/ │ │ │ │ ├── GUI Style Setting.asset │ │ │ │ └── GUI Style Setting.asset.meta │ │ │ └── EditorSetting.meta │ │ ├── Editor.meta │ │ ├── General/ │ │ │ ├── Resources/ │ │ │ │ ├── FlexiAsset/ │ │ │ │ │ ├── DefaultDataArchiveSetting.asset │ │ │ │ │ └── DefaultDataArchiveSetting.asset.meta │ │ │ │ └── FlexiAsset.meta │ │ │ └── Resources.meta │ │ ├── General.meta │ │ ├── Sample/ │ │ │ ├── EDITOR_TEST_SYSTEM.cs │ │ │ ├── EDITOR_TEST_SYSTEM.cs.meta │ │ │ ├── Scenes/ │ │ │ │ ├── Demo1.unity │ │ │ │ └── Demo1.unity.meta │ │ │ ├── Scenes.meta │ │ │ ├── Scripts/ │ │ │ │ ├── CustomDataWrapper.cs │ │ │ │ ├── CustomDataWrapper.cs.meta │ │ │ │ ├── DataContainerForSave_Sample.cs │ │ │ │ ├── DataContainerForSave_Sample.cs.meta │ │ │ │ ├── DataManagerSample.cs │ │ │ │ ├── DataManagerSample.cs.meta │ │ │ │ ├── DataManagerSample_2.cs │ │ │ │ ├── DataManagerSample_2.cs.meta │ │ │ │ ├── DemoSample.cs │ │ │ │ ├── DemoSample.cs.meta │ │ │ │ ├── DeviceAccess.cs │ │ │ │ └── DeviceAccess.cs.meta │ │ │ ├── Scripts.meta │ │ │ ├── Setting/ │ │ │ │ ├── Resources/ │ │ │ │ │ ├── DataArchiveSettingByGameplay.asset │ │ │ │ │ ├── DataArchiveSettingByGameplay.asset.meta │ │ │ │ │ ├── DataArchiveSettingBySetting.asset │ │ │ │ │ └── DataArchiveSettingBySetting.asset.meta │ │ │ │ └── Resources.meta │ │ │ └── Setting.meta │ │ ├── Sample.meta │ │ ├── Script/ │ │ │ ├── Assist/ │ │ │ │ ├── Consts.cs │ │ │ │ ├── Consts.cs.meta │ │ │ │ ├── Info/ │ │ │ │ │ ├── DataArchiveConstData.cs │ │ │ │ │ └── DataArchiveConstData.cs.meta │ │ │ │ └── Info.meta │ │ │ ├── Assist.meta │ │ │ ├── DataArchiveOperation/ │ │ │ │ ├── PlayerPrefsDataArchiveOperation.cs │ │ │ │ └── PlayerPrefsDataArchiveOperation.cs.meta │ │ │ ├── DataArchiveOperation.meta │ │ │ ├── DataType/ │ │ │ │ ├── DataType_Object.cs │ │ │ │ ├── DataType_Object.cs.meta │ │ │ │ ├── DataVector2.cs │ │ │ │ ├── DataVector2.cs.meta │ │ │ │ ├── DataVector3.cs │ │ │ │ ├── DataVector3.cs.meta │ │ │ │ ├── DataVector4.cs │ │ │ │ └── DataVector4.cs.meta │ │ │ ├── DataType.meta │ │ │ ├── Initializer/ │ │ │ │ ├── FlexiArchiveSystemInitializer.cs │ │ │ │ └── FlexiArchiveSystemInitializer.cs.meta │ │ │ ├── Initializer.meta │ │ │ ├── Manager/ │ │ │ │ ├── DefaultDataArchiveManager.cs │ │ │ │ ├── DefaultDataArchiveManager.cs.meta │ │ │ │ ├── IFlexiDataArchiveManager.cs │ │ │ │ └── IFlexiDataArchiveManager.cs.meta │ │ │ ├── Manager.meta │ │ │ ├── Other/ │ │ │ │ ├── Editor/ │ │ │ │ │ ├── Assist/ │ │ │ │ │ │ ├── CompileListener.cs │ │ │ │ │ │ └── CompileListener.cs.meta │ │ │ │ │ ├── Assist.meta │ │ │ │ │ ├── DataDetailEditorPopupWindow.cs │ │ │ │ │ ├── DataDetailEditorPopupWindow.cs.meta │ │ │ │ │ ├── FlexiArchiveMenuItems.cs │ │ │ │ │ ├── FlexiArchiveMenuItems.cs.meta │ │ │ │ │ ├── FlexiDataQueryWindow.cs │ │ │ │ │ ├── FlexiDataQueryWindow.cs.meta │ │ │ │ │ ├── FlexiGUIStyleSetting.cs │ │ │ │ │ └── FlexiGUIStyleSetting.cs.meta │ │ │ │ ├── Editor.meta │ │ │ │ ├── Logger/ │ │ │ │ │ ├── Logger.cs │ │ │ │ │ └── Logger.cs.meta │ │ │ │ └── Logger.meta │ │ │ ├── Other.meta │ │ │ ├── Setting/ │ │ │ │ ├── FlexiArchiveGlobalSetting.cs │ │ │ │ ├── FlexiArchiveGlobalSetting.cs.meta │ │ │ │ ├── FlexiArchiveSetting.cs │ │ │ │ └── FlexiArchiveSetting.cs.meta │ │ │ └── Setting.meta │ │ └── Script.meta │ └── Unity.meta ├── Engine.meta ├── LICENSE ├── README - EN.md ├── README.md ├── System/ │ ├── Assist/ │ │ ├── ArchiveManagerRegister.cs │ │ ├── ArchiveManagerRegister.cs.meta │ │ ├── DataTypeRegister.cs │ │ ├── DataTypeRegister.cs.meta │ │ ├── Info/ │ │ │ ├── DataArchiveConstData.cs │ │ │ ├── DataArchiveConstData.cs.meta │ │ │ ├── DataKeyHandler.cs │ │ │ └── DataKeyHandler.cs.meta │ │ ├── Info.meta │ │ ├── Logger.cs │ │ └── Logger.cs.meta │ ├── Assist.meta │ ├── Attributes/ │ │ ├── FlexiArchiveAttribute.cs │ │ └── FlexiArchiveAttribute.cs.meta │ ├── Attributes.meta │ ├── Base/ │ │ ├── DataGroup.cs │ │ ├── DataGroup.cs.meta │ │ ├── DataObject.cs │ │ ├── DataObject.cs.meta │ │ ├── DataTypeSystemInfo.cs │ │ ├── DataTypeSystemInfo.cs.meta │ │ ├── FlexiArchiveSystemInfo.cs │ │ ├── FlexiArchiveSystemInfo.cs.meta │ │ ├── IDataType.cs │ │ └── IDataType.cs.meta │ ├── Base.meta │ ├── DataArchiveOperation/ │ │ ├── CloneSource/ │ │ │ ├── DataArchiveSourceWrapper.cs │ │ │ └── DataArchiveSourceWrapper.cs.meta │ │ ├── CloneSource.meta │ │ ├── FileModeDataArchiveOperation.cs │ │ ├── FileModeDataArchiveOperation.cs.meta │ │ ├── Getter/ │ │ │ ├── DataArchiveOperationFactory.cs │ │ │ └── DataArchiveOperationFactory.cs.meta │ │ ├── Getter.meta │ │ ├── IO/ │ │ │ ├── IOHelper.cs │ │ │ └── IOHelper.cs.meta │ │ ├── IO.meta │ │ ├── Info/ │ │ │ ├── ArchiveOperationType.cs │ │ │ └── ArchiveOperationType.cs.meta │ │ ├── Info.meta │ │ ├── Interface/ │ │ │ ├── ICloneDataArchive.cs │ │ │ ├── ICloneDataArchive.cs.meta │ │ │ ├── IDataArchiveOperation.cs │ │ │ ├── IDataArchiveOperation.cs.meta │ │ │ ├── ISetDataArchivePath.cs │ │ │ └── ISetDataArchivePath.cs.meta │ │ ├── Interface.meta │ │ ├── PlayerPrefsDataArchiveOperation.cs │ │ ├── PlayerPrefsDataArchiveOperation.cs.meta │ │ ├── SQLDataArchiveOperation.cs │ │ └── SQLDataArchiveOperation.cs.meta │ ├── DataArchiveOperation.meta │ ├── DataSystemInfoOperation/ │ │ ├── DataSystemInfoArchiveOperation.cs │ │ ├── DataSystemInfoArchiveOperation.cs.meta │ │ ├── IDataTypeSystemInfoOperation.cs │ │ └── IDataTypeSystemInfoOperation.cs.meta │ ├── DataSystemInfoOperation.meta │ ├── DataType/ │ │ ├── Base/ │ │ │ ├── AbstractDataTypeWrapper.cs │ │ │ ├── AbstractDataTypeWrapper.cs.meta │ │ │ ├── ValueWrapper.cs │ │ │ └── ValueWrapper.cs.meta │ │ ├── Base.meta │ │ ├── DataBoolean.cs │ │ ├── DataBoolean.cs.meta │ │ ├── DataDouble.cs │ │ ├── DataDouble.cs.meta │ │ ├── DataFloat.cs │ │ ├── DataFloat.cs.meta │ │ ├── DataInteger.cs │ │ ├── DataInteger.cs.meta │ │ ├── DataLong.cs │ │ ├── DataLong.cs.meta │ │ ├── DataString.cs │ │ ├── DataString.cs.meta │ │ ├── DataType_Object.cs │ │ └── DataType_Object.cs.meta │ ├── DataType.meta │ ├── Entry/ │ │ ├── DataArchiveContainer.cs │ │ └── DataArchiveContainer.cs.meta │ ├── Entry.meta │ ├── Extension/ │ │ ├── DiskAndMemoryData.cs │ │ ├── DiskAndMemoryData.cs.meta │ │ ├── FlexiDataContainer.cs │ │ └── FlexiDataContainer.cs.meta │ ├── Extension.meta │ ├── Helper/ │ │ ├── DataArchiveOperationHelper.cs │ │ └── DataArchiveOperationHelper.cs.meta │ ├── Helper.meta │ ├── Manager/ │ │ ├── IFlexiDataArchiveManager.cs │ │ └── IFlexiDataArchiveManager.cs.meta │ ├── Manager.meta │ ├── SerializeOperation/ │ │ ├── DataTypeSerializeOperation.cs │ │ ├── DataTypeSerializeOperation.cs.meta │ │ ├── JsonReaderWithCached.cs │ │ └── JsonReaderWithCached.cs.meta │ ├── SerializeOperation.meta │ ├── Setting/ │ │ ├── ArchiveSettingWrapper.cs │ │ ├── ArchiveSettingWrapper.cs.meta │ │ ├── FlexiArchiveSetting.cs │ │ └── FlexiArchiveSetting.cs.meta │ └── Setting.meta ├── System.meta └── Third-Party Notices.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry polar: # Replace with a single Polar username buy_me_a_coffee: # Replace with a single Buy Me a Coffee username thanks_dev: # Replace with a single thanks.dev username custom: ['https://playcreator.cn/donation'] ================================================ FILE: 3rdParty/Plugins/Android/libs/arm64-v8a/libsqlite3.so.meta ================================================ fileFormatVersion: 2 guid: 949600c8665a5074da336cf807bb9da5 PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} defineConstraints: [] isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: Android: Android second: enabled: 1 settings: CPU: ARM64 - first: Any: second: enabled: 0 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android/libs/arm64-v8a.meta ================================================ fileFormatVersion: 2 guid: 2746dddf1a7693d42a1865e84cea3aeb folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android/libs/armeabi-v7a/libsqlite3.so.meta ================================================ fileFormatVersion: 2 guid: a00620409803a41f598cabed0c2ecf9f PluginImporter: serializedVersion: 1 iconMap: {} executionOrder: {} isPreloaded: 0 platformData: Android: enabled: 1 settings: CPU: ARMv7 Any: enabled: 0 settings: {} Editor: enabled: 0 settings: CPU: AnyCPU DefaultValueInitialized: true OS: AnyOS Linux: enabled: 0 settings: CPU: x86 Linux64: enabled: 0 settings: CPU: x86_64 OSXIntel: enabled: 0 settings: CPU: AnyCPU OSXIntel64: enabled: 0 settings: CPU: AnyCPU SamsungTV: enabled: 0 settings: STV_MODEL: STANDARD_13 WP8: enabled: 0 settings: CPU: AnyCPU DontProcess: False PlaceholderPath: Win: enabled: 0 settings: CPU: AnyCPU Win64: enabled: 0 settings: CPU: AnyCPU WindowsStoreApps: enabled: 0 settings: CPU: AnyCPU DontProcess: False PlaceholderPath: SDK: AnySDK iOS: enabled: 0 settings: CompileFlags: FrameworkDependencies: userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android/libs/armeabi-v7a.meta ================================================ fileFormatVersion: 2 guid: 08b2651045c57a441975bfde798f2859 folderAsset: yes timeCreated: 1445131378 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android/libs/x86/libsqlite3.so.meta ================================================ fileFormatVersion: 2 guid: fa9cbdc3a67e5fd4baeb5d0dd3f4cf71 timeCreated: 1445131383 licenseType: Free PluginImporter: serializedVersion: 1 iconMap: {} executionOrder: {} isPreloaded: 0 platformData: Any: enabled: 1 settings: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android/libs/x86.meta ================================================ fileFormatVersion: 2 guid: 450e0a9c89bf4a040b26f1fef13f5655 folderAsset: yes timeCreated: 1445131378 licenseType: Free DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android/libs.meta ================================================ fileFormatVersion: 2 guid: af644fb51ec37f3449438b780a565399 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Android.meta ================================================ fileFormatVersion: 2 guid: 5498749e113948b4995b4c7c84d6a9d2 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/LitJson.dll.meta ================================================ fileFormatVersion: 2 guid: 1027d88a1cc47844d8364a10a78de52d PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} defineConstraints: [] isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: Any: second: enabled: 1 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true - first: Windows Store Apps: WindowsStoreApps second: enabled: 0 settings: CPU: AnyCPU userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/Mono.Data.Sqlite.dll.meta ================================================ fileFormatVersion: 2 guid: 4a080d28bad4fd24eaf1b1d23e6dabf7 PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} defineConstraints: [] isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: Any: second: enabled: 1 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true - first: Windows Store Apps: WindowsStoreApps second: enabled: 0 settings: CPU: AnyCPU userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/System.Data.dll.meta ================================================ fileFormatVersion: 2 guid: b34c80b044fa8554aa6a1f50b79282d4 PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} defineConstraints: [] isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: Any: second: enabled: 1 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true - first: Windows Store Apps: WindowsStoreApps second: enabled: 0 settings: CPU: AnyCPU userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins/sqlite3.dll.meta ================================================ fileFormatVersion: 2 guid: dbd24d71814d34b478b720e43bea4f7f PluginImporter: externalObjects: {} serializedVersion: 2 iconMap: {} executionOrder: {} defineConstraints: [] isPreloaded: 0 isOverridable: 0 isExplicitlyReferenced: 0 validateReferences: 1 platformData: - first: Any: second: enabled: 1 settings: {} - first: Editor: Editor second: enabled: 0 settings: DefaultValueInitialized: true userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty/Plugins.meta ================================================ fileFormatVersion: 2 guid: e7560047bc862b3499ed8e7b11d00dcc folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: 3rdParty.meta ================================================ fileFormatVersion: 2 guid: 9eebd61acc3ed664191de3a4d15356c1 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Editor/EditorSetting/GUI Style Setting.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 6fe1c7a13b6293c449ac0bcd4d1ec1c8, type: 3} m_Name: GUI Style Setting m_EditorClassIdentifier: textAreaStyle: m_Name: TextArea m_Normal: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 1, g: 1, b: 1, a: 1} m_Hover: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 1, g: 1, b: 1, a: 1} m_Active: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 0, g: 0, b: 0, a: 1} m_Focused: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 1, g: 1, b: 1, a: 1} m_OnNormal: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 0, g: 0, b: 0, a: 1} m_OnHover: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 0, g: 0, b: 0, a: 1} m_OnActive: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 0, g: 0, b: 0, a: 1} m_OnFocused: m_Background: {fileID: 0} m_ScaledBackgrounds: [] m_TextColor: {r: 1, g: 1, b: 1, a: 1} m_Border: m_Left: 0 m_Right: 0 m_Top: 0 m_Bottom: 0 m_Margin: m_Left: 5 m_Right: 5 m_Top: 5 m_Bottom: 5 m_Padding: m_Left: 1 m_Right: 1 m_Top: 1 m_Bottom: 1 m_Overflow: m_Left: 0 m_Right: 0 m_Top: 0 m_Bottom: 0 m_Font: {fileID: 0} m_FontSize: 0 m_FontStyle: 0 m_Alignment: 0 m_WordWrap: 1 m_RichText: 1 m_TextClipping: 0 m_ImagePosition: 0 m_ContentOffset: {x: 0, y: 0} m_FixedWidth: 0 m_FixedHeight: 0 m_StretchWidth: 1 m_StretchHeight: 0 ================================================ FILE: Engine/Unity/Editor/EditorSetting/GUI Style Setting.asset.meta ================================================ fileFormatVersion: 2 guid: 50165f10765dc2a40990676c4ebd9818 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Editor/EditorSetting.meta ================================================ fileFormatVersion: 2 guid: 8da2af29a70336746b61194587747f38 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Editor.meta ================================================ fileFormatVersion: 2 guid: d60e5f25fbfd20742a14375060216310 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/General/Resources/FlexiAsset/DefaultDataArchiveSetting.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 5e9c44cf00e94936b33fcacf7af5bbe1, type: 3} m_Name: DefaultDataArchiveSetting m_EditorClassIdentifier: archiveOperationType: 2 isLog: 1 _AllowSaveDataSystemInfo: 0 _ModuleName: Default ================================================ FILE: Engine/Unity/General/Resources/FlexiAsset/DefaultDataArchiveSetting.asset.meta ================================================ fileFormatVersion: 2 guid: 5c6c3afd4448ab446b53d6e69b978de7 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/General/Resources/FlexiAsset.meta ================================================ fileFormatVersion: 2 guid: 0bcae3d330ce5014097192d4201e6e19 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/General/Resources.meta ================================================ fileFormatVersion: 2 guid: 527a0746316a9b943b16c3a4a96c5bb9 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/General.meta ================================================ fileFormatVersion: 2 guid: 5d95cd577b1e9d348b8705f5e54bf43b folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/EDITOR_TEST_SYSTEM.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using UnityEngine; using Logger = FlexiArchiveSystem.Assist.Logger; namespace FlexiArchiveSystem.Sample { [ExecuteInEditMode] public partial class DemoSample { private string write_str; private string read_str; private bool isAsync = true; private string archiveID; void OnGUI() { GUI.Label(new Rect(Screen.width/2 - 65,Screen.height - 90,130,50),"Flexi Archive System"); GUI.Label(new Rect(Screen.width/2 - 125,Screen.height - 70,280,50),"Copyright (c) 2024 温文. All rights reserved."); GUI.Label(new Rect(Screen.width/2 - 95,Screen.height - 50,200,50),"blog: https://www.playcreator.cn"); GUI.Label(new Rect(Screen.width/2 - 88,Screen.height - 30,200,50),"email: yixiangluntan@163.com"); if (Application.isPlaying == false || archiveManager == null) { GUI.Label(new Rect(10, 10, 500, 50), "Please click the play button to test."); GUI.Label(new Rect(10, 50, 500, 50), $"If you want to query data, you can go to ' {Consts.QueryArchiveToolPath} ' ."); return; } GUI.Label(new Rect(10, 10, 500, 50), $"If you want to query data, you can go to ' {Consts.QueryArchiveToolPath} ' ."); GUI.Label(new Rect(10, 50, 500, 50), $"Current Archive Index : {archiveManager.ArchiveSetting.CurrentArchiveID} ."); if (string.IsNullOrEmpty(write_str) == false) { GUI.Label(new Rect(10, 90, 500, 50), $"Write : {write_str} ."); } if (string.IsNullOrEmpty(read_str) == false) { if (string.IsNullOrEmpty(write_str) == false) { GUI.Label(new Rect(10, 90, 500, 50), $"Write : {write_str} ."); GUI.Label(new Rect(10, 130, 500, 50), $"Read : {read_str} ."); } else { GUI.Label(new Rect(10, 90, 500, 50), $"Read : {read_str} ."); } } var groundWidth = 400; var groundHeight = 200; var screenWidth = Screen.width; var screenHeight = Screen.height; var groupx = (screenWidth - groundWidth) / 2; var groupy = (screenHeight - groundHeight) / 2; GUI.BeginGroup(new Rect(groupx, groupy, groundWidth, groundHeight)); GUI.Box(new Rect(0, 0, groundWidth, groundHeight), "Select"); isAsync = GUI.Toggle(new Rect(groundWidth - 80, 2, 80, 30),isAsync, "IsAsync"); List> ele = new List>(); ele.Add(new Tuple("1.write(1-1):str", () => { write_str = Demo1_WriteStr(); })); ele.Add(new Tuple("2.read(1-1):str", () => { read_str = Demo2_ReadStrFromDisk(); })); ele.Add(new Tuple("3.write(2-2):vec2", () => { write_str = Demo5_WriteVector2(); })); ele.Add(new Tuple("4.read(2-2):vec2", () => { read_str = Demo6_ReadVector2(); })); ele.Add(new Tuple("5.write(3-1):list", () => { write_str = Demo9_WriteList(); })); ele.Add(new Tuple("6.read(3-1):list", () => { read_str = Demo10_ReadList(); })); ele.Add(new Tuple("7.write(3-2):obj", () => { write_str = Demo7_WriteObj(); })); ele.Add(new Tuple("8.read(3-2):obj", () => { read_str = Demo8_ReadObj(); })); ele.Add(new Tuple("9.Clear Cache", () => { Demo_ClearCache(); })); ele.Add(new Tuple("10.save", () => { Demo_SavePoint(isAsync); })); ele.Add(new Tuple("11.DeleteAll", () => { Demo_DeleteCurrentArchive(); })); ele.Add(new Tuple("12.Clone Archive", () => { CloneArchive(); })); for (int i = 0; i < ele.Count; i++) { int rowIndex = i / 3; int colIndex = i % (ele.Count / 4); if (GUI.Button(new Rect(10 + colIndex * 130, 30 + rowIndex * 40, 120, 30), ele[i].Item1)) { ele[i].Item2.Invoke(); } } GUI.EndGroup(); GUI.BeginGroup(new Rect((screenWidth - 200) / 2, groupy + groundHeight + 50, 200, 50)); string lastArchiveID = archiveID; string curID = archiveManager.ArchiveSetting.CurrentArchiveID.ToString(); if (lastArchiveID != curID) { lastArchiveID = curID; } archiveID = GUI.TextField(new Rect(40, 0, 120, 20), lastArchiveID); GUI.Label(new Rect(50, 25, 120, 20), "Switch Archive"); if (int.TryParse(archiveID, out var value) == false) { Logger.LOG_ERROR("Please enter the archive ID number"); archiveID = lastArchiveID; } if (string.Equals(lastArchiveID, archiveID) == false) { SwitchArchive(int.Parse(archiveID)); } GUI.EndGroup(); } } } ================================================ FILE: Engine/Unity/Sample/EDITOR_TEST_SYSTEM.cs.meta ================================================ fileFormatVersion: 2 guid: aeacf7b35ff7daf4485217cd101b18c4 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Scenes/Demo1.unity ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!29 &1 OcclusionCullingSettings: m_ObjectHideFlags: 0 serializedVersion: 2 m_OcclusionBakeSettings: smallestOccluder: 5 smallestHole: 0.25 backfaceThreshold: 100 m_SceneGUID: 00000000000000000000000000000000 m_OcclusionCullingData: {fileID: 0} --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 serializedVersion: 9 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 m_AmbientMode: 0 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 m_HaloTexture: {fileID: 0} m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} m_DefaultReflectionMode: 0 m_DefaultReflectionResolution: 128 m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 705507994} m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 0 m_LightmapEditorSettings: serializedVersion: 12 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 m_AO: 0 m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 m_FinalGather: 0 m_FinalGatherFiltering: 1 m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 m_PVRSampling: 1 m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 m_PVREnvironmentSampleCount: 500 m_PVREnvironmentReferencePointCount: 2048 m_PVRFilteringMode: 2 m_PVRDenoiserTypeDirect: 0 m_PVRDenoiserTypeIndirect: 0 m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 m_PVRFilteringGaussRadiusAO: 2 m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} m_LightingSettings: {fileID: 0} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: serializedVersion: 2 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 agentSlope: 45 agentClimb: 0.4 ledgeDropHeight: 0 maxJumpAcrossDistance: 0 minRegionArea: 2 manualCellSize: 0 cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 accuratePlacement: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} --- !u!1 &374287339 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 374287341} - component: {fileID: 374287342} m_Layer: 0 m_Name: Demo m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!4 &374287341 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 374287339} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &374287342 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 374287339} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 21dfd204c9013a9469831365823aeddf, type: 3} m_Name: m_EditorClassIdentifier: --- !u!1 &705507993 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 705507995} - component: {fileID: 705507994} m_Layer: 0 m_Name: Directional Light m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!108 &705507994 Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 705507993} m_Enabled: 1 serializedVersion: 10 m_Type: 1 m_Shape: 0 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 m_InnerSpotAngle: 21.80208 m_CookieSize: 10 m_Shadows: m_Type: 2 m_Resolution: -1 m_CustomResolution: -1 m_Strength: 1 m_Bias: 0.05 m_NormalBias: 0.4 m_NearPlane: 0.2 m_CullingMatrixOverride: e00: 1 e01: 0 e02: 0 e03: 0 e10: 0 e11: 1 e12: 0 e13: 0 e20: 0 e21: 0 e22: 1 e23: 0 e30: 0 e31: 0 e32: 0 e33: 1 m_UseCullingMatrixOverride: 0 m_Cookie: {fileID: 0} m_DrawHalo: 0 m_Flare: {fileID: 0} m_RenderMode: 0 m_CullingMask: serializedVersion: 2 m_Bits: 4294967295 m_RenderingLayerMask: 1 m_Lightmapping: 1 m_LightShadowCasterMode: 0 m_AreaSize: {x: 1, y: 1} m_BounceIntensity: 1 m_ColorTemperature: 6570 m_UseColorTemperature: 0 m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} m_UseBoundingSphereOverride: 0 m_UseViewFrustumForShadowCasterCull: 1 m_ShadowRadius: 0 m_ShadowAngle: 0 --- !u!4 &705507995 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 705507993} m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} --- !u!1 &963194225 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 963194228} - component: {fileID: 963194227} - component: {fileID: 963194226} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 --- !u!81 &963194226 AudioListener: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 963194225} m_Enabled: 1 --- !u!20 &963194227 Camera: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 963194225} m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 2 m_BackGroundColor: {r: 0.23584908, g: 0.23584908, b: 0.23584908, a: 0} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 x: 0 y: 0 width: 1 height: 1 near clip plane: 0.3 far clip plane: 1000 field of view: 60 orthographic: 0 orthographic size: 5 m_Depth: -1 m_CullingMask: serializedVersion: 2 m_Bits: 4294967295 m_RenderingPath: -1 m_TargetTexture: {fileID: 0} m_TargetDisplay: 0 m_TargetEye: 3 m_HDR: 1 m_AllowMSAA: 1 m_AllowDynamicResolution: 0 m_ForceIntoRT: 0 m_OcclusionCulling: 1 m_StereoConvergence: 10 m_StereoSeparation: 0.022 --- !u!4 &963194228 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 963194225} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 1, z: -10} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ================================================ FILE: Engine/Unity/Sample/Scenes/Demo1.unity.meta ================================================ fileFormatVersion: 2 guid: b5b7a0e9c69ff32429a5f4df930f5383 DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Scenes.meta ================================================ fileFormatVersion: 2 guid: 9021c738a2dde8d4ea53518e9be6ea83 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Scripts/CustomDataWrapper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem.Sample { /// /// 1.create construct method /// /// public class CustomDataType : AbstractDataTypeWrapper { public CustomDataType(string dataStr) : base(dataStr) { } public override bool Equals(CustomData another) { throw new System.NotImplementedException(); } } /// /// 2.override "ToString(CustomData)" function if would know detail data /// /// public class CustomData { public string author = "温文"; public int code = 1; public double luckly = 1.0f; public override string ToString() { return "author: " + author + " code: " + code + " luckly: " + luckly; } } /// /// 3.If it is a complex type that litjson can't serialize, /// # you can choose to extend ValueWrapper class, /// # I wrapped the conversion method for you. /// public class CustomDataWrapper : ValueWrapper { public string author = "温文"; public int code = 1; public double luckly = 1.0f; public override void ValueToTheWrapper(CustomData2 value) { //convert author = value.author; code = value.code; luckly = (double)value.luckly; //float -> double } public override CustomData2 WrapperToValue() { //new object throw new System.NotImplementedException(); } } public class CustomData2 { public string author = "温文"; public int code = 1; public float luckly = 1.0f; public override string ToString() { return "author: " + author + " code: " + code + " luckly: " + luckly; } } } ================================================ FILE: Engine/Unity/Sample/Scripts/CustomDataWrapper.cs.meta ================================================ fileFormatVersion: 2 guid: 0d453c1988606d04abeffb1a62f8180f MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Scripts/DataContainerForSave_Sample.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; using FlexiArchiveSystem.Extension; namespace FlexiArchiveSystem.Sample { public class DataContainerForSave_Sample : FlexiDataContainer { public string author { get => GetMemoryValue("FlexiDataSave","author"); set => ModifyValue("FlexiDataSave","author", value); } public int age { get => GetMemoryValue("FlexiDataSave","age"); set => ModifyValue("FlexiDataSave","age", value); } public DiskAndMemoryData author_storage { get => GetValue("FlexiDataSave","author"); } public DiskAndMemoryData age_storage { get => GetValue("FlexiDataSave","age"); } public DataContainerForSave_Sample(IFlexiDataArchiveManager dataArchiveManager) { SetDataArchiveManager(dataArchiveManager); } } public class DataContainerForSave_Sample2 : IFlexiWriteOrReadArchiveOperation { public IFlexiDataArchiveManager DataArchiveManager => DataManagerSample.instance; public string author { get => GetMemoryValue("FlexiDataSave","author"); set => ModifyValue("FlexiDataSave","author", value); } public int age { get => GetMemoryValue("FlexiDataSave","age"); set => ModifyValue("FlexiDataSave","age", value); } public DiskAndMemoryData GetValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { return DataArchiveManager.GetValue(GroupKey, SubKey); } public TValue GetDiskValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { return DataArchiveManager.GetDiskValue(GroupKey, SubKey); } public TValue GetMemoryValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { return DataArchiveManager.GetMemoryValue(GroupKey, SubKey); } public void ModifyValue(string GroupKey, string SubKey, TValue value) where TDataType: AbstractDataTypeWrapper { DataArchiveManager.ModifyValue(GroupKey, SubKey, value); } } } ================================================ FILE: Engine/Unity/Sample/Scripts/DataContainerForSave_Sample.cs.meta ================================================ fileFormatVersion: 2 guid: 3cec93c9daeb4954b90701a247ff28ac timeCreated: 1728734142 ================================================ FILE: Engine/Unity/Sample/Scripts/DataManagerSample.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.Setting; using UnityEngine; namespace FlexiArchiveSystem.Sample { public class DataManagerSample : IFlexiDataArchiveManager { public static DataManagerSample instance = new DataManagerSample(); protected override ArchiveSettingWrapper LoadDataArchiveSettingFromDisk() { return new ArchiveSettingWrapper(Resources.Load("DataArchiveSettingByGameplay")); } } } ================================================ FILE: Engine/Unity/Sample/Scripts/DataManagerSample.cs.meta ================================================ fileFormatVersion: 2 guid: ced5faf4c61746e6994927ab95f903de timeCreated: 1723792418 ================================================ FILE: Engine/Unity/Sample/Scripts/DataManagerSample_2.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.Setting; using UnityEngine; namespace FlexiArchiveSystem.Sample { public class DataManagerSample_2 : IFlexiDataArchiveManager { public static DataManagerSample_2 instance = new DataManagerSample_2(); protected override ArchiveSettingWrapper LoadDataArchiveSettingFromDisk() { return new ArchiveSettingWrapper(Resources.Load("DataArchiveSettingBySetting")); } } } ================================================ FILE: Engine/Unity/Sample/Scripts/DataManagerSample_2.cs.meta ================================================ fileFormatVersion: 2 guid: 1cf7e559947d4db996b822cedfbc3235 timeCreated: 1723801476 ================================================ FILE: Engine/Unity/Sample/Scripts/DemoSample.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Collections.Generic; using System.IO; using UnityEngine; using Random = UnityEngine.Random; namespace FlexiArchiveSystem.Sample { public partial class DemoSample : MonoBehaviour { private IFlexiDataArchiveManager archiveManager; private DataContainerForSave_Sample dataContainer; /// /// Launch Flexi-Archive System; /// private void Awake() { if (Application.isPlaying == false) { return; } //Earlier versions of Android require permission from the device to read and write. //高版本的安卓需要向设备申请权限,才能进行读写。 DeviceAccess.ApplyAccess(); DataArchiveConstData.USER_KEY = "Wenen"; //Set User‘s key archiveManager = DefaultDataArchiveManager.Instance; // Use the default // archiveManager = DataManagerSample.instance;// Use the custom archiveManager.Init(); archiveID = archiveManager.GetLastArchiveID().ToString(); dataContainer = new DataContainerForSave_Sample(archiveManager); } private void Update() { if (Input.GetKeyDown(KeyCode.A)) { Demo11_WriteDic(); } if (Input.GetKeyDown(KeyCode.B)) { Demo11_WriteDic(); } if (Input.GetKeyDown(KeyCode.J)) { TestPropertyBind_Write("温文",18); } if (Input.GetKeyDown(KeyCode.N)) { TestPropertyBind_Write("Miracle",19); } if (Input.GetKeyDown(KeyCode.K)) { TestPropertyBind_ReadMemory(); } if (Input.GetKeyDown(KeyCode.L)) { TestPropertyBind_ReadDisk(); } } private string Demo1_WriteStr() { DataObject dataObject = archiveManager.GetDataObject("group1", "key1"); DataString dataString = dataObject.GetData(); dataString.Write(char.ConvertFromUtf32(Random.Range(65, 123))); Debug.Log(string.Format($"[{Path.Combine("group1", "key1")}]: write a str :{dataString.data}")); return dataString.data; } private string Demo2_ReadStrFromDisk() { DataObject dataObject = archiveManager.GetDataObject("group1", "key1"); DataString dataString = dataObject.GetData(); string str = dataString.diskData; Debug.Log(string.Format($"[{Path.Combine("group1", "key1")}]: read a str from disk: {str}")); return str; } private string Demo3_WriteInt() { DataObject dataObject = archiveManager.GetDataObject("group2", "key1"); DataInteger dataInteger = dataObject.GetData(); dataInteger.Write(Random.Range(0, 5)); Debug.Log(string.Format( $"[{Path.Combine("group2", "key1")}]: write a number of type int {dataInteger.data}")); return dataInteger.data.ToString(); } private string Demo4_ReadIntFromDisk() { DataObject dataObject = archiveManager.GetDataObject("group2", "key1"); DataInteger dataInteger = dataObject.GetData(); Debug.Log(string.Format( $"[{Path.Combine("group2", "key1")}]: read a int from disk : {dataInteger.diskData}")); return dataInteger.diskData.ToString(); } private string Demo5_WriteVector2() { DataObject dataObject = archiveManager.GetDataObject("group2", "key2"); DataVector2 dataVector2 = dataObject.GetData(); dataVector2.Write(new Vector2(Random.Range(0, 100), Random.Range(0, 100))); Debug.Log(string.Format($"[{Path.Combine("group2", "key2")}]: write a vector2 :{dataVector2.data}")); return dataVector2.data.ToString(); } private string Demo6_ReadVector2() { DataObject dataObject = archiveManager.GetDataObject("group2", "key2"); DataVector2 dataVector2 = dataObject.GetData(); Debug.Log(string.Format( $"[{Path.Combine("group2", "key2")}]: read a vector2 from disk:{dataVector2.diskData}")); return dataVector2.diskData.ToString(); } private string Demo7_WriteObj() { DataObject dataObject = archiveManager.GetDataObject("group3", "key2"); DataType_Object DataType_Object = dataObject.GetData(); DataType_Object.Write(new Vector3Wrapper(new Vector3(6,6,6))); Debug.Log(string.Format($"[{Path.Combine("group3", "key2")}]: write a object :{DataType_Object.data}")); return DataType_Object.data.ToString(); } private string Demo8_ReadObj() { DataObject dataObject = archiveManager.GetDataObject("group3", "key2"); DataType_Object DataType_Object = dataObject.GetData(); string str = "null"; if (DataType_Object.diskData != null) { Vector3 vector3 = (Vector3Wrapper)DataType_Object.diskData; str = vector3.ToString(); } Debug.Log(string.Format($"[{Path.Combine("group3", "key2")}]: read a object :{str}")); return str; } private string Demo9_WriteList() { DataObject dataObject = archiveManager.GetDataObject("group3", "key1"); DataStructList dataStructList = dataObject.GetData>(); List list = new List(); list.Add(Random.Range(0, 5)); list.Add(Random.Range(0, 5)); list.Add(Random.Range(0, 5)); list.Add(Random.Range(0, 5)); dataStructList.Write(list); string log = dataStructList.data.ToString() + " - [ "; foreach (var ele in dataStructList.data) { log += ele.ToString(); log += ","; } log = log.Remove(log.Length - 1); log += " ]"; Debug.Log(($"[{Path.Combine("group3", "key1")}]: write a list :{log}")); return log; } private string Demo10_ReadList() { DataObject dataObject = archiveManager.GetDataObject("group3", "key1"); DataStructList dataStructList = dataObject.GetData>(); string log = "null"; if (dataStructList.diskData != null) { log = dataStructList.diskData.ToString() + " - [ "; foreach (var ele in dataStructList.diskData) { log += ele.ToString(); log += ","; } log = log.Remove(log.Length - 1); log += " ]"; } Debug.Log(($"[{Path.Combine("group3", "key1")}]: write a list :{log}")); return log; } private string Demo11_WriteDic() { DataObject dataObject = archiveManager.GetDataObject("group3", "key3"); DataDictionary dataDictionary = dataObject.GetData>(); Dictionary dictionary = new Dictionary(); dictionary.Add(1.ToString(),new Vector3(1,1,1)); dictionary.Add(2.ToString(),new Vector3(2,2,2)); dictionary.Add(3.ToString(),new Vector3(3,4,4)); dataDictionary.Write(dictionary); string log = dataDictionary.data.ToString() + " - " + dataDictionary.ToString(); Debug.Log(($"[{Path.Combine("group3", "key1")}]: write a dictionary :{log}")); return log; } private string Demo12_ReadDic() { DataObject dataObject = archiveManager.GetDataObject("group3", "key3"); DataDictionary dataDictionary = dataObject.GetData>(); string log = "null"; if (dataDictionary.diskData != null) { log = dataDictionary.diskData.ToString() + " - " + dataDictionary.ToString(); } Debug.Log(($"[{Path.Combine("group3", "key1")}]: write a dictionary :{log}")); return log; } private void Demo_ClearCache() { archiveManager.ClearMemoryCache(); Debug.Log(string.Format($"Clear Memory Cache")); } private void Demo_SavePoint(bool isAsync) { Debug.Log(string.Format($"save archive")); if (isAsync) { archiveManager.SaveAsync(() => { Debug.Log("async save successfully");}); } else { archiveManager.Save(); Debug.Log("save successfully"); } } private void Demo_DeleteCurrentArchive() { archiveManager.DeleteAll(); Debug.Log(string.Format($"Delete Current All Data")); } private void CloneArchive() { archiveManager.InstantiateNewArchive(); Debug.Log(string.Format($"Clone New Archive From Current Archive ")); } private void SwitchArchive(int archiveID) { archiveManager.SwitchArchiveID(archiveID); Debug.Log(string.Format($"Switch Archive {archiveID}")); } private void TestPropertyBind_Write(string author, int age) { Debug.Log(string.Format($"[TestPropertyBind_Write] 尝试写入 author: {author} | age:{age}")); dataContainer.author = author; dataContainer.age = age; } private void TestPropertyBind_ReadDisk() { Debug.Log(string.Format($"[TestPropertyBind_Disk] author: {dataContainer.author_storage.diskData} | age:{dataContainer.age_storage.diskData}")); } private void TestPropertyBind_ReadMemory() { Debug.Log(string.Format($"[TestPropertyBind_Memory] author: {dataContainer.author} | age:{dataContainer.age}")); } } } ================================================ FILE: Engine/Unity/Sample/Scripts/DemoSample.cs.meta ================================================ fileFormatVersion: 2 guid: 21dfd204c9013a9469831365823aeddf MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Scripts/DeviceAccess.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using UnityEngine.Android; namespace FlexiArchiveSystem { public class DeviceAccess { public static void ApplyAccess() { #if UNITY_ANDROID if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageRead)) { Permission.RequestUserPermission(Permission.ExternalStorageRead); } if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite)) { Permission.RequestUserPermission(Permission.ExternalStorageWrite); } #endif } } } ================================================ FILE: Engine/Unity/Sample/Scripts/DeviceAccess.cs.meta ================================================ fileFormatVersion: 2 guid: ab00007ae1a09ff46a2a41e6545c4cd9 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Scripts.meta ================================================ fileFormatVersion: 2 guid: 2926649f92f24d429fc3b5d50011f0f0 timeCreated: 1722222080 ================================================ FILE: Engine/Unity/Sample/Setting/Resources/DataArchiveSettingByGameplay.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 5e9c44cf00e94936b33fcacf7af5bbe1, type: 3} m_Name: DataArchiveSettingByGameplay m_EditorClassIdentifier: archiveOperationType: 2 isLog: 1 _AllowSaveDataSystemInfo: 0 _ModuleName: GamePlay ================================================ FILE: Engine/Unity/Sample/Setting/Resources/DataArchiveSettingByGameplay.asset.meta ================================================ fileFormatVersion: 2 guid: 4735d84488c6a204695afc4163777636 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Setting/Resources/DataArchiveSettingBySetting.asset ================================================ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 5e9c44cf00e94936b33fcacf7af5bbe1, type: 3} m_Name: DataArchiveSettingBySetting m_EditorClassIdentifier: archiveOperationType: 0 isLog: 1 _AllowSaveDataSystemInfo: 0 _ModuleName: Setting ================================================ FILE: Engine/Unity/Sample/Setting/Resources/DataArchiveSettingBySetting.asset.meta ================================================ fileFormatVersion: 2 guid: 4d127514d3d0b52438c67c8865521e6c NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Setting/Resources.meta ================================================ fileFormatVersion: 2 guid: cf5b2b61fa3c4a54bb5c427dffa260ef folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample/Setting.meta ================================================ fileFormatVersion: 2 guid: 55392754d92ffce46be431ba7e049e64 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Sample.meta ================================================ fileFormatVersion: 2 guid: 86dbbc65a80849f4bd1e8f17111a158c folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Script/Assist/Consts.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem { public static class Consts { public const string QueryArchiveToolPath = "Tools/FlexiArchive/DataMonitor"; public const string ClearAllArchiveToolPath = "Tools/FlexiArchive/ClearAllArchive"; } } ================================================ FILE: Engine/Unity/Script/Assist/Consts.cs.meta ================================================ fileFormatVersion: 2 guid: 575199a978a04621b7a2e7ed8fb47343 timeCreated: 1724489179 ================================================ FILE: Engine/Unity/Script/Assist/Info/DataArchiveConstData.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using UnityEngine; namespace FlexiArchiveSystem { public static partial class DataArchiveConstData { private static string AppPersistentDataPath = Application.persistentDataPath; /// /// there are some platform can require special persistent path for save data /// example as weixin. /// This is part of the SDK business layer, so the system doesn't want to take on any more responsibility. /// please check persistent path is corrent on current paltform, if system with problem /// /// public static void SetPersistentDataPath(string path) { AppPersistentDataPath = path; } } } ================================================ FILE: Engine/Unity/Script/Assist/Info/DataArchiveConstData.cs.meta ================================================ fileFormatVersion: 2 guid: 3dcfc66c6cd04fb99eb06fb0174124f3 timeCreated: 1724326533 ================================================ FILE: Engine/Unity/Script/Assist/Info.meta ================================================ fileFormatVersion: 2 guid: c45d150676d54baea5cf187375d86856 timeCreated: 1724326523 ================================================ FILE: Engine/Unity/Script/Assist.meta ================================================ fileFormatVersion: 2 guid: 78452e3ea00e403cbb71ba4c3c18d6c8 timeCreated: 1724326518 ================================================ FILE: Engine/Unity/Script/DataArchiveOperation/PlayerPrefsDataArchiveOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Collections.Generic; using UnityEngine; using System; using System.Threading.Tasks; using FlexiArchiveSystem.ArchiveOperation; using LitJson; namespace FlexiArchiveSystem.ArchiveOperation { /// /// Playerprefs Mode /// notice: For performance reasons, this method does not currently support multiple archive coexistence. /// notice: 出于性能考虑,因此该方式目前不支持多存档共存。 /// internal partial class PlayerPrefsDataArchiveOperation : IDataArchiveOperation { private string _ArchiveSystemName; public string ArchiveSystemName => _ArchiveSystemName; public bool IsValidation { get { return IsActive; } } private bool IsActive = false; private Dictionary groupDataMap = new Dictionary(); private DataArchiveOperationHelper archiveOperationHelper; public DataArchiveOperationHelper ArchiveOperationHelper { get { if (archiveOperationHelper == null) { SetDataArchiveOperationHelper(DataArchiveOperationFactory.GetDataArchiveOperationHelper()); } return archiveOperationHelper; } } public List AllGroupKeys; public void SetDataArchiveOperationHelper(DataArchiveOperationHelper helper) { helper.Init(ArchiveSystemName); helper.UpdateDirtyState(_archiveID); archiveOperationHelper = helper; } private int _archiveID; public async void Init(string moudleName, int archiveID) { _ArchiveSystemName = moudleName; SetArchiveID(archiveID); AllGroupKeys = await LoadAllGroupKeyFromDisk(); IsActive = true; } public void SetArchiveID(int archiveID) { _archiveID = archiveID; } public void DataPersistent(string groupKey, string dataKey, string dataStr) { bool hasExistedBefore =TryGetJsonData(groupKey, out JsonData jsonData); bool isRewriteGroupKeys = hasExistedBefore == false; jsonData[dataKey] = JsonMapper.ToObject(dataStr); PlayerPrefs.SetString(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey), jsonData.ToJson()); if (isRewriteGroupKeys) { TryRecordKey(groupKey); } } public void DataPersistent(params DataObject[] dataObjects) { throw new NotImplementedException(); } #pragma warning disable CS1998 public async Task DataPersistentAsync(string groupKey, string dataKey, string dataStr, Action complete) { throw new NotImplementedException("PlayerPrefs does not support asynchronous saving"); } #pragma warning restore CS1998 #pragma warning disable CS1998 public async Task DataPersistentAsync(Action complete, params DataObject[] dataObjects) { throw new NotImplementedException("PlayerPrefs does not support asynchronous saving"); } #pragma warning restore CS1998 public string Read(string groupKey, string dataKey) { bool isGet = TryGetJsonData(groupKey, out JsonData jsonData); if (isGet == false) { return ""; } string jsonResult; try { JsonData concreteData_JsonData = jsonData[dataKey]; jsonResult = concreteData_JsonData == null || concreteData_JsonData["value"] == null ? "" : concreteData_JsonData.ToJson(); } catch (KeyNotFoundException) { jsonResult = ""; } return jsonResult; } #pragma warning disable CS1998 public async Task DeleteAll() { if (AllGroupKeys == null) { AllGroupKeys = await LoadAllGroupKeyFromDisk(); } if (AllGroupKeys != null) { foreach (var groupKey in AllGroupKeys) { PlayerPrefs.DeleteKey(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey)); } } TryRemoveAllGroupKey(); } #pragma warning restore CS1998 public void Delete(string groupKey, string dataKey) { bool isGet = TryGetJsonData(groupKey, out JsonData jsonData); if (isGet == false) { return; } jsonData[dataKey] = null; PlayerPrefs.SetString(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey), jsonData.ToJson()); } public void DeleteGroup(string groupKey) { if (PlayerPrefs.HasKey(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey)) == false) { return; } PlayerPrefs.DeleteKey(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey)); ArchiveOperationHelper.RemoveGroupKey(groupKey); } public virtual void TryRecordKey(string groupKey) { if (AllGroupKeys != null) { AllGroupKeys.Add(groupKey); } ArchiveOperationHelper.RecordKey(_archiveID, groupKey); } public void TryRemoveAllGroupKey() { ArchiveOperationHelper.DeleteAllGroupKeyFromDisk(); } private async Task> LoadAllGroupKeyFromDisk() { return await ArchiveOperationHelper.GetAllGroupKey(); } private bool TryGetJsonData(string groupKey, out JsonData jsonData) { jsonData = null; if (groupDataMap.TryGetValue(groupKey, out jsonData) == false) { string str = LoadFromDisk(groupKey); if (string.IsNullOrEmpty(str)) { jsonData = new JsonData(); groupDataMap.Add(groupKey, jsonData); return false; } jsonData = JsonMapper.ToObject(str); groupDataMap.Add(groupKey, jsonData); } return true; } private string LoadFromDisk(string groupKey) { if (PlayerPrefs.HasKey(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey)) == false) { return ""; } string str = PlayerPrefs.GetString(DataArchiveConstData.GetGroupKeyInPlayerPrefs(groupKey), ""); return str; } public void Dispose() { AllGroupKeys = null; groupDataMap = null; IsActive = false; } public async Task DisposeAsync() { Dispose(); } } } ================================================ FILE: Engine/Unity/Script/DataArchiveOperation/PlayerPrefsDataArchiveOperation.cs.meta ================================================ fileFormatVersion: 2 guid: 6e444f7919894acca8b502e223274fde timeCreated: 1722233311 ================================================ FILE: Engine/Unity/Script/DataArchiveOperation.meta ================================================ fileFormatVersion: 2 guid: ab0dd4dcb62a4c37899bc743c9df421d timeCreated: 1724293379 ================================================ FILE: Engine/Unity/Script/DataType/DataType_Object.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using UnityEngine; namespace FlexiArchiveSystem { public partial class DataType_Object { public static implicit operator DataType_Object(Vector2 value) { DataType_Object wrapperObject = new DataType_Object(""); wrapperObject._dataWrapper.value = (new Vector2Wrapper(value)); return wrapperObject; } public static implicit operator DataType_Object(Vector3 value) { DataType_Object wrapperObject = new DataType_Object(""); wrapperObject._dataWrapper.value = (new Vector3Wrapper(value)); return wrapperObject; } public static implicit operator DataType_Object(Vector4 value) { DataType_Object wrapperObject = new DataType_Object(""); wrapperObject._dataWrapper.value = (new Vector4Wrapper(value)); return wrapperObject; } } } ================================================ FILE: Engine/Unity/Script/DataType/DataType_Object.cs.meta ================================================ fileFormatVersion: 2 guid: df3819d44e6f427c9defc036831f9964 timeCreated: 1726199867 ================================================ FILE: Engine/Unity/Script/DataType/DataVector2.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; using UnityEngine; namespace FlexiArchiveSystem { public class DataVector2 : AbstractDataTypeWrapper { public DataVector2(string dataStr) : base(dataStr) { } public override bool Equals(Vector2Wrapper another) { return another.Equals(data); } } [System.Serializable] public struct Vector2Wrapper { public float x; public float y; public Vector2Wrapper(Vector2 value) { x = value.x; y = value.y; } public Vector2Wrapper(int x, int y) { this.x = x; this.y = y; } public static implicit operator Vector2Wrapper(Vector2 value) { return new Vector2Wrapper(value); } public static implicit operator Vector2(Vector2Wrapper wrapper) { return new Vector2((float)wrapper.x, (float)wrapper.y); } public override string ToString() { return string.Format("({0},{1})", x, y); } } } ================================================ FILE: Engine/Unity/Script/DataType/DataVector2.cs.meta ================================================ fileFormatVersion: 2 guid: e58f8b81a4d14ad5b7e9f7b5a5630cf2 timeCreated: 1724380559 ================================================ FILE: Engine/Unity/Script/DataType/DataVector3.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; using UnityEngine; namespace FlexiArchiveSystem { public class DataVector3 : AbstractDataTypeWrapper { public DataVector3(string dataStr) : base(dataStr) { } public override bool Equals(Vector3Wrapper another) { return another.Equals(data); } } [System.Serializable] public struct Vector3Wrapper { public float x; public float y; public float z; public Vector3Wrapper(Vector3 value) { x = value.x; y = value.y; z = value.z; } public Vector3Wrapper(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public static implicit operator Vector3Wrapper(Vector3 value) { return new Vector3Wrapper(value); } public static implicit operator Vector3(Vector3Wrapper wrapper) { return new Vector3((float)wrapper.x, (float)wrapper.y, (float)wrapper.z); } public override string ToString() { return string.Format("({0},{1},{2})", x, y, z); } } } ================================================ FILE: Engine/Unity/Script/DataType/DataVector3.cs.meta ================================================ fileFormatVersion: 2 guid: b3f8a436e0564a8ea1c7692693f6131c timeCreated: 1725245066 ================================================ FILE: Engine/Unity/Script/DataType/DataVector4.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; using UnityEngine; namespace FlexiArchiveSystem { public class DataVector4 : AbstractDataTypeWrapper { public DataVector4(string dataStr) : base(dataStr) { } public override bool Equals(Vector4Wrapper another) { return another.Equals(data); } } [System.Serializable] public struct Vector4Wrapper { public float x; public float y; public float z; public float w; public Vector4Wrapper(Vector4 value) { x = value.x; y = value.y; z = value.z; w = value.w; } public Vector4Wrapper(float x, float y, float z, float w) { this.x = x; this.y = y; this.z = z; this.w = w; } public static implicit operator Vector4Wrapper(Vector4 value) { return new Vector4Wrapper(value); } public static implicit operator Vector4(Vector4Wrapper wrapper) { return new Vector4(wrapper.x,wrapper.y,wrapper.z,wrapper.w); } public override string ToString() { return string.Format("({0},{1},{2},{3})", x, y, z, w); } } } ================================================ FILE: Engine/Unity/Script/DataType/DataVector4.cs.meta ================================================ fileFormatVersion: 2 guid: 5f724e4570fc4d9f9ac952744c20170d timeCreated: 1725258669 ================================================ FILE: Engine/Unity/Script/DataType.meta ================================================ fileFormatVersion: 2 guid: ac36bc0913714c28ab9445a02bad6b0f timeCreated: 1724380542 ================================================ FILE: Engine/Unity/Script/Initializer/FlexiArchiveSystemInitializer.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Threading; using UnityEngine; using Logger = FlexiArchiveSystem.Assist.Logger; namespace FlexiArchiveSystem { public static class FlexiArchiveSystemInitializer { [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] static void Init() { } } } ================================================ FILE: Engine/Unity/Script/Initializer/FlexiArchiveSystemInitializer.cs.meta ================================================ fileFormatVersion: 2 guid: b9015f59c25340bc8dfd7a2e7a89fde3 timeCreated: 1725347027 ================================================ FILE: Engine/Unity/Script/Initializer.meta ================================================ fileFormatVersion: 2 guid: d436d33e45e5418ca570c3cdaa213111 timeCreated: 1725347370 ================================================ FILE: Engine/Unity/Script/Manager/DefaultDataArchiveManager.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.Setting; using UnityEngine; namespace FlexiArchiveSystem { /// /// Flexi Archive System 为你准备了一个默认的存档系统实例 /// Flexi Archive System provides you with a default archive system instance /// public sealed class DefaultDataArchiveManager : IFlexiDataArchiveManager { private static DefaultDataArchiveManager instance; public static DefaultDataArchiveManager Instance { get { if (instance == null) { instance = new DefaultDataArchiveManager(); // instance.Init(); } return instance; } } protected override ArchiveSettingWrapper LoadDataArchiveSettingFromDisk() { return new ArchiveSettingWrapper( Resources.Load("FlexiAsset/DefaultDataArchiveSetting")); } } } ================================================ FILE: Engine/Unity/Script/Manager/DefaultDataArchiveManager.cs.meta ================================================ fileFormatVersion: 2 guid: a1e421a66236635409b8bc2631c20985 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Script/Manager/IFlexiDataArchiveManager.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using FlexiArchiveSystem.Assist; using FlexiArchiveSystem.DataType.Base; using FlexiArchiveSystem.Entry; using FlexiArchiveSystem.Setting; using UnityEngine; namespace FlexiArchiveSystem { public abstract partial class IFlexiDataArchiveManager : IDisposable { public FlexiArchiveSetting ArchiveSetting { get; protected set; } protected DataArchiveContainer ArchiveContainer; public void Init() { var settingInfo = LoadDataArchiveSettingFromDisk(); if (settingInfo.ArchiveSetting == null) { return; } SetDataArchiveSetting(settingInfo.ArchiveSetting as FlexiArchiveSetting); InitDataArchiveSetting(); InitDataArchiveContainer(); ArchiveManagerRegister.instance.Register(this); ListenQuit(); InitInEditor(); } [Conditional("UNITY_EDITOR")] private void InitInEditor() { } private void ListenQuit() { UnityEngine.Application.quitting += OnApplicationQuit; } public void SetDataArchiveSetting(FlexiArchiveSetting setting) { #if UNITY_EDITOR if (UnityEngine.Application.isPlaying == false) { ArchiveSetting = UnityEngine.ScriptableObject.CreateInstance(); ArchiveSetting.ArchiveOperationMode = setting.ArchiveOperationMode; ArchiveSetting.GetType().GetField("_ModuleName", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ArchiveSetting, setting.ModuleName); ArchiveSetting.hideFlags = UnityEngine.HideFlags.DontSave; return; } #endif ArchiveSetting = setting; } public void InitDataArchiveSetting() { ArchiveSetting.Init(); } protected void InitDataArchiveContainer() { if (ArchiveContainer != null) { return; } ArchiveContainer = new DataArchiveContainer(ArchiveSetting); } public void InstantiateNewArchive() { ArchiveContainer.InstantiateNewArchive(); } public DiskAndMemoryData GetValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { DataObject dataObject = GetDataObject(GroupKey, SubKey); TDataType dataType = dataObject.GetData(); return new DiskAndMemoryData(dataType.data, dataType.diskData); } public TValue GetDiskValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { DataObject dataObject = GetDataObject(GroupKey, SubKey); TDataType dataType = dataObject.GetData(); return dataType.diskData; } public TValue GetMemoryValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { DataObject dataObject = GetDataObject(GroupKey, SubKey); TDataType dataType = dataObject.GetData(); return dataType.data; } public void ModifyValue(string GroupKey, string SubKey, TValue value) where TDataType: AbstractDataTypeWrapper { DataObject dataObject = GetDataObject(GroupKey, SubKey); TDataType dataType = dataObject.GetData(); dataType.Write(value); } /// /// advise to use ModifyValue /// /// /// /// /// [Obsolete("advise to use ModifyValue")] public void ModifyValue(string GroupKey, string SubKey, TValue value) { DataObject dataObject = GetDataObject(GroupKey, SubKey); Type abstractDataTypeMeta = DataTypeBinder.GetByValueType(); IDataType idataType = dataObject.GetData(abstractDataTypeMeta); idataType.WriteByGenericObject(value); } public DataObject GetDataObject(string groupKey, string dataKey) { return ArchiveContainer.GetDataObject(groupKey, dataKey); } public DataGroup GetDataGroup(string groupKey) { return ArchiveContainer.GetDataGroup(groupKey); } public void SwitchArchiveID(int archiveID) => ArchiveContainer.SwitchArchive(archiveID); public int GetLastArchiveID() { List ids = ArchiveSetting.GetAllArchiveID(); if (ids == null) { return ArchiveSetting.CurrentArchiveID; } return ids[ids.Count - 1]; } public FlexiArchiveSystemInfo GetArchiveSystemInfo(int archiveID) { return default(FlexiArchiveSystemInfo); } public void Save() => ArchiveContainer.Save(); public void SaveAsync(Action complete = null) => ArchiveContainer.SaveAsync(complete); public void SaveGroup(string group_key) { ArchiveContainer.SaveGroup(group_key); } public void SaveGroup(params string[] groups) { ArchiveContainer.SaveGroup(groups); } public void Delete(string groupKey, string dataKey) { ArchiveContainer.Delete(groupKey, dataKey); } public void DeleteAll() { ArchiveContainer.DeleteAll(); ArchiveSetting.ClearAllArchiveIDCacheInMemory(); } public void ClearMemoryCache() => ArchiveContainer.ClearMemoryCache(); public virtual void Dispose() { } private void OnApplicationQuit() { if (Application.isPlaying == false) { UnityEngine.Application.quitting -= OnApplicationQuit; } if (ArchiveSetting != null) { ArchiveSetting.DataArchiveOperation?.Dispose(); ArchiveSetting.DataTypeSystemInfoOperation?.Dispose(); if (Application.isPlaying) { ArchiveSetting.Dispose(); } ArchiveSetting = null; } Dispose(); GC.Collect(); GC.WaitForPendingFinalizers(); } } } ================================================ FILE: Engine/Unity/Script/Manager/IFlexiDataArchiveManager.cs.meta ================================================ fileFormatVersion: 2 guid: 23b6fd5e8184458599ff236aaf9fe3e7 timeCreated: 1723792570 ================================================ FILE: Engine/Unity/Script/Manager.meta ================================================ fileFormatVersion: 2 guid: 39ab7918ff20480d9f5e1268d11273f2 timeCreated: 1724327490 ================================================ FILE: Engine/Unity/Script/Other/Editor/Assist/CompileListener.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using UnityEditor; namespace FlexiArchiveSystem.U3DEditor { public class CompileListener : AssetPostprocessor { private static Action actionWhenCompile; public static void RegisterEvent(Action action) { actionWhenCompile += action; } public static void RemoveEvent(Action action) { actionWhenCompile -= action; } static void OnPostprocessAllAssets(string[] importedAssetPaths) { foreach (var path in importedAssetPaths) { if (path.EndsWith(".cs")) { actionWhenCompile?.Invoke(); return; } } } } } ================================================ FILE: Engine/Unity/Script/Other/Editor/Assist/CompileListener.cs.meta ================================================ fileFormatVersion: 2 guid: 7cc0746c40fa4adaaf13d011fd4f314a timeCreated: 1724400475 ================================================ FILE: Engine/Unity/Script/Other/Editor/Assist.meta ================================================ fileFormatVersion: 2 guid: 61e813f7f5a74f24b4ee923ba8e765c4 timeCreated: 1724400488 ================================================ FILE: Engine/Unity/Script/Other/Editor/DataDetailEditorPopupWindow.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using UnityEditor; using UnityEngine; namespace FlexiArchiveSystem.U3DEditor { public class DataDetailEditorPopupWindow : PopupWindowContent { public string Key { get; protected set; } public FlexiDataQueryWindow.ResultWrapper ResultWrapper { get; protected set; } private Vector2 scrollPos; public DataDetailEditorPopupWindow(string key, FlexiDataQueryWindow.ResultWrapper result) { Key = key; ResultWrapper = result; } public override Vector2 GetWindowSize() { return new Vector2(400, 200); } public override void OnGUI(Rect rect) { EditorGUILayout.BeginVertical(); scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Key:", GUILayout.Width(50)); EditorGUILayout.TextField(Key, FlexiGUIStyleSetting.Instance.textAreaStyle); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Memory:", GUILayout.Width(50)); EditorGUILayout.TextArea(ResultWrapper.result, FlexiGUIStyleSetting.Instance.textAreaStyle); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Disk:", GUILayout.Width(50)); EditorGUILayout.TextArea(ResultWrapper.diskResult, FlexiGUIStyleSetting.Instance.textAreaStyle, GUILayout.ExpandHeight(true)); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndScrollView(); EditorGUILayout.EndVertical(); ; } } } ================================================ FILE: Engine/Unity/Script/Other/Editor/DataDetailEditorPopupWindow.cs.meta ================================================ fileFormatVersion: 2 guid: 83ba4a9bdf8b43cbb6f1d55154d9453e timeCreated: 1723545369 ================================================ FILE: Engine/Unity/Script/Other/Editor/FlexiArchiveMenuItems.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.IO; using System.Linq; using System.Reflection; using UnityEditor; namespace FlexiArchiveSystem.U3DEditor { public class FlexiArchiveMenuItems { [MenuItem(Consts.ClearAllArchiveToolPath,false,0)] public static void ClearAllArchive() { var path = DataArchiveConstData.UserArchiveDirectoryPath; if (Directory.Exists(path)) { Directory.Delete(path, true); } Type IFlexiType = typeof(IFlexiDataArchiveManager); Assembly assembly = Assembly.GetAssembly(IFlexiType); Type[] types = assembly.GetTypes(); var archiveMgrTypes= types.Where((t)=> t.BaseType != null && t.BaseType.Name == IFlexiType.Name); foreach (var type in archiveMgrTypes) { // IFlexiDataArchiveManager archiveMgr = (IFlexiDataArchiveManager)type.GetField("instance", BindingFlags.Static|BindingFlags.Public).GetValue(null); IFlexiDataArchiveManager archiveMgr = Activator.CreateInstance(type) as IFlexiDataArchiveManager; archiveMgr.Init(); if (archiveMgr.ArchiveSetting != null) { archiveMgr.ArchiveSetting.DeleteArchiveIDData(); } } } } } ================================================ FILE: Engine/Unity/Script/Other/Editor/FlexiArchiveMenuItems.cs.meta ================================================ fileFormatVersion: 2 guid: c8aa6f0acf894a60922d5fb6c1f5e470 timeCreated: 1725588940 ================================================ FILE: Engine/Unity/Script/Other/Editor/FlexiDataQueryWindow.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using FlexiArchiveSystem.Assist; using FlexiArchiveSystem.Setting; using UnityEditor; using UnityEngine; using Logger = FlexiArchiveSystem.Assist.Logger; using Object = UnityEngine.Object; namespace FlexiArchiveSystem.U3DEditor { public class FlexiDataQueryWindow : EditorWindow { private string _GroupKey; private string _SubKey; private static FlexiDataQueryWindow _window; private IFlexiDataArchiveManager DataArchiveManager; private FlexiArchiveSetting DataArchiveSetting; public Dictionary keyValuePairs = new Dictionary(); public Queue removeResultQueue = new Queue(); private bool isQueryError; private bool isNonArchiveError; public class ResultWrapper { public string result; public string diskResult; public string resultType; } public List AllArchiveID; public int selectArchiveID; public Vector2 scrollPos; bool _foldoutValue; public Object field_archiveSetting; [MenuItem(Consts.QueryArchiveToolPath, false ,-100)] public static void ShowWindow() { _window = EditorWindow.GetWindow(typeof(FlexiDataQueryWindow),false,"Flexi-ArchiveMonitor") as FlexiDataQueryWindow; _window.minSize = new Vector2(600, 100); string key = _window.GetLastQueryKey(); if (string.IsNullOrEmpty(key) == false) { var items = DataKeyHandler.GetAndProcessKeyCollection(key); _window.UpdateKeyField(items.Item1, items.Item2); } EditorApplication.playModeStateChanged += _window.OnPlayModeStateChanged; CompileListener.RegisterEvent(_window.WhenCompile); if (Application.isPlaying == false) { InitAllArchiveManager(); } if (_window.DataArchiveManager == null) { string moduleName = _window.GetLastSelectArchiveSettingName(); if (string.IsNullOrEmpty(moduleName)) { moduleName = "Default"; } _window.DataArchiveManager = ArchiveManagerRegister.instance.FindByArchiveSetting(moduleName); } } private void WhenCompile() { StopArticleMgrService(); } public void OnPlayModeStateChanged(PlayModeStateChange state) { if (state == PlayModeStateChange.ExitingEditMode) { Close(); } } private void OnDestroy() { CompileListener.RemoveEvent(WhenCompile); EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; StopArticleMgrService(); if (string.IsNullOrEmpty(_GroupKey) || string.IsNullOrEmpty(_SubKey)) { return; } RecordLastQueryKey(DataKeyHandler.CombieGroupAndDataKey(_GroupKey, _SubKey)); } private void StopArticleMgrService() { if (DataArchiveManager == null) { return; } if (Application.isPlaying == false) { DataArchiveManager.Dispose(); var methodInfo = typeof(IFlexiDataArchiveManager).GetMethod("OnApplicationQuit", BindingFlags.NonPublic); methodInfo?.Invoke(DataArchiveManager, null); } } void UpdateKeyField(string groupKey, string subKey) { _GroupKey = groupKey; _SubKey = subKey; } public string GetLastQueryKey() { return PlayerPrefs.GetString("DataQueryEditor_LastQuery", ""); } public void RecordLastQueryKey(string key) { PlayerPrefs.SetString("DataQueryEditor_LastQuery", key); } public string GetLastSelectArchiveSettingName() { return PlayerPrefs.GetString("DataQueryEditor_LastSelectArchiveSettingName", ""); } public void RecordSelectArchiveSettingName(string moduleName) { PlayerPrefs.SetString("DataQueryEditor_LastSelectArchiveSettingName", moduleName); } private void OnGUI() { //input key EditorGUILayout.BeginVertical(); EditorGUILayout.Space(10); EditorGUILayout.BeginHorizontal(); if (field_archiveSetting == null) { EditorGUILayout.HelpBox("please set the archive Settings", MessageType.Error, true); } else { if (DataArchiveManager == null) { EditorGUILayout.HelpBox("No archive system found(未查询到对应的存档系统)", MessageType.Error, true); } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); EditorGUILayout.BeginHorizontal(); GUILayout.Label("setting:", GUILayout.Width(50)); EditorGUI.BeginChangeCheck(); field_archiveSetting = EditorGUILayout.ObjectField(field_archiveSetting, typeof(FlexiArchiveSetting), false); bool isChangeSetting = EditorGUI.EndChangeCheck(); if (field_archiveSetting == null && DataArchiveManager !=null && DataArchiveManager.ArchiveSetting != null) { field_archiveSetting = DataArchiveManager.ArchiveSetting; isChangeSetting = field_archiveSetting != null; } if (isChangeSetting) { if (field_archiveSetting != null) { var setting = field_archiveSetting as FlexiArchiveSetting; var mgr = ArchiveManagerRegister.instance.FindByArchiveSetting(setting); DataArchiveManager = mgr; if (mgr != null) { DataArchiveSetting = DataArchiveManager.ArchiveSetting; if (string.IsNullOrEmpty(DataArchiveSetting.ModuleName) == false) { field_archiveSetting.name = DataArchiveSetting.ModuleName; } AllArchiveID = DataArchiveSetting.GetAllArchiveID(); isNonArchiveError = AllArchiveID == null || AllArchiveID.Count == 0; selectArchiveID = DataArchiveSetting.CurrentArchiveID; RecordSelectArchiveSettingName(DataArchiveSetting.ModuleName); } } } if (isNonArchiveError) { EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("no archived data", MessageType.Warning, true); } else { EditorGUILayout.Space(1, false); GUILayout.Label("select archive:", GUILayout.Width(90)); EditorGUI.BeginDisabledGroup(Application.isPlaying || DataArchiveSetting == null); if (EditorGUILayout.DropdownButton(new GUIContent(DataArchiveConstData.GetArchiveKey(selectArchiveID)), FocusType.Keyboard, GUILayout.Width(position.width * 0.4f))) { if (Application.isPlaying == false) { GenericMenu genericMenu = new GenericMenu(); for (int i = 0; i < AllArchiveID.Count; i++) { int index = i; genericMenu.AddItem(new GUIContent(DataArchiveConstData.GetArchiveKey(AllArchiveID[i])), selectArchiveID == AllArchiveID[i], () => { SelectArchiveIDItem(index); }); genericMenu.AddSeparator(string.Empty); //分割线 } genericMenu.ShowAsContext(); } } EditorGUI.EndDisabledGroup(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); EditorGUILayout.BeginHorizontal(); EditorGUILayout.HelpBox("enter the data key you want to query:", MessageType.Info, true); // GUILayout.Label("",GUILayout.Width(125)); float halfWidth = _window.position.width / 2; EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("GroupKey: ", GUILayout.Width(60)); _GroupKey = EditorGUILayout.TextField("", _GroupKey, GUILayout.ExpandWidth(true)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Subkey: ", GUILayout.Width(60)); _SubKey = EditorGUILayout.TextField("", _SubKey, GUILayout.ExpandWidth(true)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(20); EditorGUILayout.BeginHorizontal(); bool clickQueryBtn = GUILayout.Button(new GUIContent("Query", "click to watch value"), GUI.skin.button, GUILayout.Height(21)); if (clickQueryBtn) { if (DataArchiveManager == null) { isQueryError = true; } else { OnClickQueryButton(); } } EditorGUILayout.EndHorizontal(); if (isQueryError) { EditorGUILayout.HelpBox("key does not exist", MessageType.Error, true); } if (keyValuePairs.Count > 0) { EditorGUILayout.Space(20); scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false, GUILayout.Width(position.width), GUILayout.Height(position.height / 2)); EditorGUILayout.BeginVertical(GUI.skin.scrollView); EditorGUILayout.Separator(); foreach (var pair in keyValuePairs) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("key: ", GUILayout.Width(30)); EditorGUILayout.LabelField($"{pair.Key}", GUI.skin.box, GUILayout.Width(position.width * 0.1f), GUILayout.Height(22)); EditorGUILayout.LabelField(new GUIContent("Memory: "), GUILayout.Width(50)); EditorGUILayout.LabelField(pair.Value.result, GUI.skin.box, GUILayout.Width(position.width * 0.1f), GUILayout.Height(22)); EditorGUILayout.LabelField(new GUIContent("Disk: "), GUILayout.Width(40)); EditorGUILayout.LabelField(pair.Value.diskResult, GUI.skin.box, GUILayout.Width(position.width * 0.1f), GUILayout.Height(22)); EditorGUILayout.LabelField(new GUIContent("Type: "), GUILayout.Width(40)); EditorGUILayout.LabelField(pair.Value.resultType, GUI.skin.box, GUILayout.Width(position.width * 0.1f), GUILayout.Height(22)); EditorGUILayout.Space(1); if (GUILayout.Button("Detail", GUILayout.ExpandWidth(true))) { ClickShowDetail(pair.Key); } if (GUILayout.Button("Remove", GUILayout.ExpandWidth(true))) { ClickRemoveMonitor(pair.Key); } EditorGUILayout.Space(10); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); } EditorGUILayout.EndVertical(); GUILayout.EndScrollView(); } EditorGUILayout.EndVertical(); OnGUIEnd(); //value } private void OnGUIEnd() { RemoveResultInQueue(); } private void OnClickQueryButton() { isQueryError = false; var dataObject = DataArchiveManager.GetDataObject(_GroupKey, _SubKey); string fullKey = DataKeyHandler.CombieGroupAndDataKey(_GroupKey, _SubKey); try { ResultWrapper result = QueryResult(dataObject, fullKey); SetResult(fullKey, result); AddMonitor(dataObject); } catch (Exception e) { isQueryError = true; #if UNITY_EDITOR && EDITOR_DEV_WENEN Assist.Logger.LOG_ERROR(e.Message); #endif } } private ResultWrapper QueryResult(DataObject dataObject, string fullKey) { var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(fullKey); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; Type dataTypeSystemType = null; try { dataTypeSystemType = DataArchiveSetting.DataTypeSystemInfoOperation.GetTypeOfDataValue(groupKey, dataKey); #if UNITY_EDITOR && EDITOR_DEV_WENEN if (dataTypeSystemType == null) { Logger.LOG_ERROR("The SystemInfo information is missing"); } #endif } catch (Exception) { Logger.LOG_ERROR("An error occurred while obtaining SystemInfo."); } Type valueType = dataTypeSystemType.BaseType.GetGenericArguments()[0]; var methodInfo_GetData = dataObject.GetType().GetMethod(nameof(dataObject.GetData),new Type[]{}); methodInfo_GetData = methodInfo_GetData.MakeGenericMethod(dataTypeSystemType); object dataType = methodInfo_GetData.Invoke(dataObject, null); var methodInfo_DiskToStr = dataTypeSystemType.GetMethod("DiskDataToString", BindingFlags.NonPublic | BindingFlags.Instance); object diskDataStr = methodInfo_DiskToStr.Invoke(dataType, null); ResultWrapper resultWrapper = new ResultWrapper(); resultWrapper.result = dataType.ToString(); resultWrapper.diskResult = (string)diskDataStr; resultWrapper.resultType = valueType.Name; return resultWrapper; } private void RefreshResult(string key) { var keyCollection = DataKeyHandler.GetAndProcessKeyCollection(key); DataObject dataObject = DataArchiveManager.GetDataObject(keyCollection.Item1, keyCollection.Item2); ResultWrapper resultWrapper = QueryResult(dataObject, key); UpdateResult(key, resultWrapper.result, resultWrapper.diskResult); } private void SetResult(string key, ResultWrapper result) { keyValuePairs[key] = result; } private void UpdateResult(string key, string result, string diskResult) { keyValuePairs[key].result = result; keyValuePairs[key].diskResult = diskResult; } private bool RemoveResult(string key) { return keyValuePairs.Remove(key); } private void RemoveResultInQueue() { while (removeResultQueue.Count != 0) { RemoveResult(removeResultQueue.Dequeue()); } } private void AddMonitor(DataObject dataObject) { dataObject.OnDirtyHandler += RefreshResult; dataObject.OnPersistentHandler += RefreshResult; } private void RemoveMonitor(DataObject dataObject) { dataObject.OnDirtyHandler -= RefreshResult; dataObject.OnPersistentHandler -= RefreshResult; } private void ClickShowDetail(string key) { var mousePosInWindowRect = Event.current.mousePosition; Rect rect = new Rect(mousePosInWindowRect, Vector2.zero); PopupWindow.Show(rect, new DataDetailEditorPopupWindow(key, keyValuePairs[key])); } private void ClickRemoveMonitor(string key) { var keyCollection = DataKeyHandler.GetAndProcessKeyCollection(key); DataObject dataObject = DataArchiveManager.GetDataObject(keyCollection.Item1, keyCollection.Item2); RemoveMonitor(dataObject); removeResultQueue.Enqueue(key); } private void SelectArchiveIDItem(int index) { var id = AllArchiveID[index]; if (selectArchiveID == id) { return; } selectArchiveID = id; DataArchiveSetting.SetArchiveID(selectArchiveID, false); DataArchiveSetting.CreateOrRebuildArchiveOperation(); DataArchiveManager.ClearMemoryCache(); keyValuePairs.Clear(); } private static void InitAllArchiveManager() { Type IFlexiType = typeof(IFlexiDataArchiveManager); Assembly assembly = Assembly.GetAssembly(IFlexiType); Type[] types = assembly.GetTypes(); var archiveMgrTypes= types.Where((t)=> t.BaseType != null && t.BaseType.Name == IFlexiType.Name); foreach (var type in archiveMgrTypes) { // IFlexiDataArchiveManager archiveMgr = (IFlexiDataArchiveManager)type.GetField("instance", BindingFlags.Static|BindingFlags.Public).GetValue(null); IFlexiDataArchiveManager archiveMgr = Activator.CreateInstance(type) as IFlexiDataArchiveManager; archiveMgr.Init(); } } } } ================================================ FILE: Engine/Unity/Script/Other/Editor/FlexiDataQueryWindow.cs.meta ================================================ fileFormatVersion: 2 guid: 1f3357f9aee6be24c9c3d4517e7a94ad MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Script/Other/Editor/FlexiGUIStyleSetting.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.IO; using UnityEditor; using UnityEngine; namespace FlexiArchiveSystem.U3DEditor { #if UNITY_EDITOR && EDITOR_DEV_WENEN [CreateAssetMenu(menuName = "Flexi Archive System/GUIStyleSetting")] #endif public class FlexiGUIStyleSetting : ScriptableObject { public GUIStyle textAreaStyle; private static FlexiGUIStyleSetting instance; public static FlexiGUIStyleSetting Instance { get { if (instance == null) { instance = AssetDatabase.LoadAssetAtPath(Path.Combine(GetAssetToEnginePath(),"Unity", "Editor", "EditorSetting", "GUI Style Setting.asset")); } return instance; } } static string GetAssetToEnginePath() { string assetPath = GetRootPath(); int index = assetPath.IndexOf("Engine"); return assetPath.Substring(0,index + 6); } static string GetRootPath() { string _scriptName = "FlexiGUIStyleSetting"; string[] guidArray = AssetDatabase.FindAssets(_scriptName); foreach (string guid in guidArray) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); if (assetPath.EndsWith(_scriptName + ".cs")) { return assetPath; } } return null; } } } ================================================ FILE: Engine/Unity/Script/Other/Editor/FlexiGUIStyleSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 6fe1c7a13b6293c449ac0bcd4d1ec1c8 timeCreated: 1723548842 ================================================ FILE: Engine/Unity/Script/Other/Editor.meta ================================================ fileFormatVersion: 2 guid: 09bf52b9dd41c20439006a2f42f751c4 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Script/Other/Logger/Logger.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://unitymake.com // email: yixiangluntan@163.com //------------------------------------------------- using UnityEngine; namespace FlexiArchiveSystem.Assist { public static partial class Logger { public static void LOG_ERROR(string log) { Debug.LogError(log); } public static void LOG_WARNING(string log) { Debug.LogWarning(log); } public static void LOG(string log) { Debug.Log(log); } } } ================================================ FILE: Engine/Unity/Script/Other/Logger/Logger.cs.meta ================================================ fileFormatVersion: 2 guid: e357d44ffe3b4ce79c6609e70a0773d7 timeCreated: 1724305766 ================================================ FILE: Engine/Unity/Script/Other/Logger.meta ================================================ fileFormatVersion: 2 guid: f7b01f2b9e584f33b3520635194ba636 timeCreated: 1724305760 ================================================ FILE: Engine/Unity/Script/Other.meta ================================================ fileFormatVersion: 2 guid: 520b5860acef9b84dbe6738a0471ae9a folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity/Script/Setting/FlexiArchiveGlobalSetting.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using UnityEngine; namespace FlexiArchiveSystem.Setting { [CreateAssetMenu(fileName = "GlobalSetting", menuName = "Flexi Archive System/GlobalSetting")] public class FlexiArchiveGlobalSetting : ScriptableObject { private static FlexiArchiveGlobalSetting _instance; public static FlexiArchiveGlobalSetting Instance { get { if (_instance == null) { _instance = Resources.Load("GlobalSetting"); } return _instance; } } [SerializeField] private int _MaxIOCheckTime = 1000; //ms public int MaxIOCheckTime => _MaxIOCheckTime; public void OnEnable() { if (_instance == null) { _instance = this; } } } } ================================================ FILE: Engine/Unity/Script/Setting/FlexiArchiveGlobalSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 9fbcc1e36c7c47b492a89f56a01b4654 timeCreated: 1725518670 ================================================ FILE: Engine/Unity/Script/Setting/FlexiArchiveSetting.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using FlexiArchiveSystem.ArchiveOperation; using UnityEngine; namespace FlexiArchiveSystem.Setting { [CreateAssetMenu(fileName = "DataArchiveSetting", menuName = "Flexi Archive System/DataArchiveSetting")] public partial class FlexiArchiveSetting : ScriptableObject, IArchiveSetting, IDisposable { [SerializeField] private ArchiveOperationType archiveOperationType = ArchiveOperationType.Sqlite; public ArchiveOperationType ArchiveOperationMode { get => archiveOperationType; set => archiveOperationType = value; } [SerializeField] private bool isLog = true; public bool IsLog => isLog; [Header("是否要在玩家设备上存储数据的类型信息")] [Tooltip("通常是不需要的。在玩家设备上关闭该选项不会影响数据的存档。该信息只是对应数据的辅助信息,仅为了辅助开发环境的检视。")] [SerializeField] private bool _AllowSaveDataSystemInfo = false; public bool IsAllowSaveDataSystemInfoInPlayerDevice => _AllowSaveDataSystemInfo; [Header("Archive System ID")] [SerializeField] private string _ModuleName; public string ModuleName => _ModuleName; public int CurrentArchiveID { get; private set; } [NonSerialized] private List _AllArchiveID = null; public List AllArchiveID => _AllArchiveID; public IDataArchiveOperation DataArchiveOperation { get; set; } public DataSystemInfoArchiveOperation DataTypeSystemInfoOperation { get; set; } public void Init() { CurrentArchiveID = LoadCurrentArchiveIDFromDisk(); CreateOrRebuildArchiveOperation(); } private int LoadCurrentArchiveIDFromDisk() { return PlayerPrefs.GetInt(DataArchiveConstData.GetPrefsKey_CUR_ARCHIVE(ModuleName), DataArchiveConstData.DefaultStartArchiveID); } public int GetNextArchiveID() { GetAllArchiveID(); var nextArchiveID = CurrentArchiveID + 1; while (_AllArchiveID.Contains(nextArchiveID)) { nextArchiveID += 1; } return nextArchiveID; } public void SetArchiveID(int val, bool isUpdateToDisk = true) { if (CurrentArchiveID == val) { return; } CurrentArchiveID = val; RecordCurArchiveIDIntoMemory(CurrentArchiveID); if (isUpdateToDisk) { PlayerPrefs.SetInt(DataArchiveConstData.GetPrefsKey_CUR_ARCHIVE(ModuleName), CurrentArchiveID); } } public void DeleteArchiveIDData() { PlayerPrefs.DeleteKey(DataArchiveConstData.GetPrefsKey_CUR_ARCHIVE(ModuleName)); } public void RefreshArchiveOperation() { DataArchiveOperation.Dispose(); DataArchiveOperation.Init(ModuleName, CurrentArchiveID); DataArchiveOperation.SetDataArchiveOperationHelper(DataArchiveOperation.ArchiveOperationHelper); RefreshArchiveSystemInfoOperation(); } public void SwitchArchive(int archiveID) { // if (CurrentArchiveID != archiveID) { } SetArchiveID(archiveID); CreateOrRebuildArchiveOperation(); } public void RefreshArchiveSystemInfoOperation() { #if !UNITY_EDITOR if (IsAllowSaveDataSystemInfoInPlayerDevice == false) { return; } #endif DataTypeSystemInfoOperation.Dispose(); DataTypeSystemInfoOperation.Init(ModuleName, CurrentArchiveID); DataTypeSystemInfoOperation.SetDataArchiveOperationHelper(DataTypeSystemInfoOperation.ArchiveOperationHelper); } public void CreateOrRebuildArchiveOperation() { DataArchiveOperation = DataArchiveOperationFactory.CreateArchiveOperationObject(archiveOperationType,ModuleName, CurrentArchiveID); DataArchiveOperation.Init(ModuleName,CurrentArchiveID); RebuildArchiveSystemInfoOperationInEditor(); } private void RebuildArchiveSystemInfoOperationInEditor() { #if !UNITY_EDITOR if (IsAllowSaveDataSystemInfoInPlayerDevice == false) { return; } #endif DataTypeSystemInfoOperation = DataArchiveOperationFactory.CreateArchiveSystemInfoOperationObject(archiveOperationType, ModuleName, CurrentArchiveID); DataTypeSystemInfoOperation.Init(ModuleName, CurrentArchiveID); } public List GetAllArchiveID() { if (_AllArchiveID == null) { _AllArchiveID = GetAllArchiveIDFromDisk(); } return _AllArchiveID; } private void RecordCurArchiveIDIntoMemory(int id) { if (_AllArchiveID != null && _AllArchiveID.IndexOf(id) == -1) { _AllArchiveID.Add(id); } } public void ClearAllArchiveIDCacheInMemory() { _AllArchiveID = null; } private List GetAllArchiveIDFromDisk() { List allArchiveID = null; switch (archiveOperationType) { case ArchiveOperationType.FileMode: case ArchiveOperationType.Sqlite: string archiveRootDirectoryPath = DataArchiveConstData.GetUserCertainArchiveSystemDirectoryPath(ModuleName); if (Directory.Exists(archiveRootDirectoryPath) == false) { return null; } string[] infos = Directory.GetDirectories(archiveRootDirectoryPath); if (infos != null && infos.Length > 0) { allArchiveID = new List(infos.Length); for (int i = 0; i < infos.Length; i++) { string prefix = DataArchiveConstData.Prefix_ArchiveIDKey; int startIndex = infos[i].LastIndexOf(prefix); int id_Index = startIndex + prefix.Length; int id = int.Parse(infos[i].Substring(id_Index)); allArchiveID.Add(id); } } else { allArchiveID = new List(1); allArchiveID[0] = DataArchiveConstData.DefaultStartArchiveID; } break; default: throw new Exception("ERROR:ERROR: The current archive mode does not support the coexistence of multiple archives"); } if (allArchiveID != null && allArchiveID.Count > 1) { //sort allArchiveID.Sort(); } return allArchiveID; } public void Dispose() { CurrentArchiveID = 0; _AllArchiveID = null; DataArchiveOperation = null; DataTypeSystemInfoOperation = null; } } } ================================================ FILE: Engine/Unity/Script/Setting/FlexiArchiveSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 6fd2974bdefc42498d1a3fa9d708c3dd timeCreated: 1724294575 ================================================ FILE: Engine/Unity/Script/Setting.meta ================================================ fileFormatVersion: 2 guid: 1b73f44c3d574524b5d459acc6dcc307 timeCreated: 1724294575 ================================================ FILE: Engine/Unity/Script.meta ================================================ fileFormatVersion: 2 guid: d9597fa3e6e9f8c4db92078f6255e47f folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine/Unity.meta ================================================ fileFormatVersion: 2 guid: 7b87d1cbce04d164e9fa9fa96b1989a2 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Engine.meta ================================================ fileFormatVersion: 2 guid: 71dec0f268593634482a4c61d28e6dfc folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: LICENSE ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: README - EN.md ================================================ # Flexi Archive System [![license](https://img.shields.io/badge/%20license-LGPL--2.1-brightgreen?link=https%3A%2F%2Fgithub.com%2Fwenen-creator%2FFlexiArchiveSystem%2Fblob%2Fmaster%2FLICENSE)](https://github.com/wenen-creator/FlexiArchiveSystem/blob/master/LICENSE) [![license](https://img.shields.io/badge/Author-%E6%B8%A9%E6%96%87-blue?color=%2333A1C9)](https://github.com/wenen-creator)   *Flexi Archive* is a data archiving tool designed specifically for Unity3D.   Just like the name *Flexi Archive*, *Flexi Archive* is designed with the concept of *Flexible*, aiming to provide a flexible and powerful solution to meet the complex archiving needs through its characteristics of high scalability, easy to use, high performance and comprehensive tools.   In *Flexi Archive System* you can easily save almost anything with a few lines of code **cross-platform**, while *Flexi Archive System* with its highly scalable architecture design, Allows you to customize data types and archiving policies and data formats easily according to actual needs.    *Flexi Archive System* uses **efficient** storage mechanisms. By default, it adopts the principle of on-demand loading, and adopts a large number of optimization strategies such as batching, asynchronous IO, caching mechanism, grouping strategy, dirty mark, etc., to ensure that users can respond quickly when they perform a large number of frequent data operations. Can easily deal with the complex requirements of the game. ## Quick Start   It is recommended that you open the **Sample** case before using *Flexi Archive*.   In the Sample case, you can quickly learn the core functions of *Flexi Archive System*. ![img](https://github.com/wenen-creator/FlexiArchiveSystem/blob/dev/Misc/img/preview01.PNG) ## Document   [Flexi-Archive - Manual](https://www.playcreator.cn/flexi-archive/)   [Unity-Android application read and write permissions configuration process](https://www.playcreator.cn/archives/unity/3987) ## System features ### 1.Supports multiple archiving mechanisms   You can [clone](https://www.playcreator.cn/docs/flexi-archive/manual/clone-archive/) a new archive for the current one when the time is right. The archives are isolated. Modifying one archive does not affect other archives.   Of course, you can also freely [switch](https://www.playcreator.cn/docs/flexi-archive/manual/switch-archive/), [clone](https://www.playcreator.cn/docs/flexi-archive/manual/clone-archive/), [delete](https://www.playcreator.cn/docs/flexi-archive/manual/del-archive/) the archive. ### 2.Supports saving any complex type or custom type   Flexi Archive System allows you to easily add new data types and archive policies, allowing you to archive custom complex types of data.   Currently, the system supports the following types: | ----- | ----- | ----- | |:----------:|:-------:|:-------:| | float | double | int | | long | bool | string | | vector2 | vector3 | vector4 | | object | list | array | | dictionary | custom | ····· |   If you need to archive a custom type, you do not need to care about what you do during the archiving process, and you do not need to make changes to the system. You are only responsible for creating a CustomData and an AbstractDataType concrete type to transform complex data according to the type requirements supported by Litjson0.19 .[See LitJson documentation for details](https://litjson.net/blog/2023/11/litjson-v0.19.0-released)   It is recommended that you rewrite the ToString method while writing the Wrapper, so that the data can be displayed in plain text in the development environment. example code (Plan A): ```C# /// /// 1.create construct method /// public class CustomDataType : AbstractDataType { public CustomDataType(string dataStr) : base(dataStr){} } /// /// 2.override "ToString(CustomData)" function if would know detail data /// public class CustomData { public string author = "温文"; public int code = 1; public double luckly = 1.0f; public override string ToString() { return "author: " + author + " code: " + code + " luckly: " + luckly; } } ``` example code (Plan B): See: [Create a custom data type - Flexi Archive](https://www.playcreator.cn/docs/flexi-archive/manual/create-custom-data/) ### 3.Support for object fields and data binding   In addition to holding an Archive of DataObject operations, Flexi Archive also provides an object field and data binding scheme. You can bind archive data to the properties of the object. This means that your access to and assignment to field members is equivalent to reading and writing to the archived data.   This binding mechanism simplifies the process of data management, eliminating the need for you to manually write process code to handle data reads and writes, greatly simplifying the archiving process.   See: [Object fields and data binding - Simplify the archiving process](https://www.playcreator.cn/docs/flexi-archive/manual/properties-bind-data/) ### 4.Supports multiple serialization modes   Support File, PlayerPrefs, SQL-DB asynchronous serialization (archive/read) mode. Depending on your project's module requirements and performance considerations, you are free to decide which serialization format to use for your module archiving system.The default is SQL-DB serialization.   Multi-archive support: 1. File mode: Support multiple archives 2. PlayerPrefs approach: Multiple archives are not supported for performance reasons 3. SQL-DB approach: Supports multiple archives   My analysis: 1. File mode (JSON) : suitable for projects with moderate archive requirements, convenient for cloud archive upload. 2. PlayerPrefs mode: It is suitable for single archive with small amount of data and small amount of archive in each group, and access is faster. For example, record a user operation, the user's local Settings, etc. 3. SQL-DB mode:It is suitable for projects with large amount of archive requirements. The reading overhead and compression ratio are lower than that of File mode in most cases. ### 5.Savepoint   You need to trigger the save operation at the right time. Otherwise, your modifications will only change the data in Memory.   It is worth mentioning that Flexi Archive System will only archive data that has changed asynchronously. ```C# archiveManager.SaveAsync(() => { Debug.Log("async save successfully");}); ```   See:[Save archive](https://www.playcreator.cn/docs/flexi-archive/manual/save-archive/) ### 6.Use Grouping strategy   Flexi Archive System uses GroupKey + DataKey grouping strategy, you can group data according to your business.   Proper grouping helps reduce the overhead of archiving. ### 7.Support the coexistence of multiple account archives on the same device   Set the USER_KEY after the user has successfully logged in. If your application does not have a login business, you do not need to set it. example: ``` C# void Into() { DataArchiveConstData.USER_KEY = "Wenen"; } ``` ### 8.Support for creating multiple archive systems   You are free to create as many different archive systems as you want, depending on the module of your application. See:[Creating an archive system](https://www.playcreator.cn/docs/flexi-archive/manual/create-archive-system/)   It is convenient for you to customize the extension archive system according to the specific module, and you can also choose the serialization archive method that is more suitable for the module. ### 9.Data archive monitoring tool   The Flexi Archive System provides a data query tool with the system layer, which allows you to monitor data for changes in real time (both non-runtime and runtime). ![img](https://github.com/wenen-creator/FlexiArchiveSystem/blob/dev/Misc/img/preview02.PNG) ### 10.Performance   Flexi Archive System adopts an efficient storage mechanism. By default, it adopts the principle of on-demand loading, and adopts a large number of optimization strategies such as asynchronous IO, caching mechanism, grouping strategy and dirty mark to ensure that when a large number of frequent data operations are carried out, it can also respond quickly, and avoid performance problems such as frame rate fluctuations in complex situations as much as possible. ## About the Author author: 温文(Chinese, a game developer) blog: https://www.playcreator.cn email: yixiangluntan@163.com ================================================ FILE: README.md ================================================ # Flexi Archive System [![license](https://img.shields.io/badge/%20license-LGPL--2.1-brightgreen?link=https%3A%2F%2Fgithub.com%2Fwenen-creator%2FFlexiArchiveSystem%2Fblob%2Fmaster%2FLICENSE)](https://github.com/wenen-creator/FlexiArchiveSystem/blob/master/LICENSE) [![license](https://img.shields.io/badge/Author-%E6%B8%A9%E6%96%87-blue?color=%2333A1C9)](https://github.com/wenen-creator)   *Flexi Archive* 是一个专门为 Unity3D 设计的数据存档工具。   正如 *Flexi Archive* 名字一样,*Flexi Archive* 以 **Flexible** 为设计理念,旨在通过其高度可扩展性、易上手、高性能以及完善的工具等特点,提供一个满足复杂存档需求的灵活而强大的解决方案。   在 *Flexi Archive System* 中你可以用轻松地几行代码 **跨平台** 保存几乎任何东西,同时 *Flexi Archive System* 以其高度可扩展的架构设计,允许你根据实际需求**轻松**的自定义数据类型和存档策略、数据格式。    *Flexi Archive System* 系统采用了**高效**的存储机制。默认采用按需载入原则,通过合批、异步IO、缓存机制、分组策略、脏标记等大量优化策略,确保用户在进行大量频繁的数据操作时,也能够快速响应。得以轻松应对游戏中复杂需求。 ## 快速入门   建议你在使用 *Flexi Archive* 前,先打开 **Sample** 案例。   在 Sample 案例中,你可以快速学习到 *Flexi Archive System* 的核心功能。 ![img](https://github.com/wenen-creator/FlexiArchiveSystem/blob/dev/Misc/img/preview01.PNG) ## 文档   [Flexi-Archive官方文档 - 温文](https://www.playcreator.cn/flexi-archive/)   [Unity-Android申请读写权限配置流程 - 温文](https://www.playcreator.cn/archives/unity/3987) ## 系统特点 ### 1.支持多存档机制   你可以在合适的时机,为当前存档[克隆](https://www.playcreator.cn/docs/flexi-archive/manual/clone-archive/)一份新的存档。存档间是隔离的,修改某个存档,不会对其他存档造成影响。   当然你也可以自由的[切换](https://www.playcreator.cn/docs/flexi-archive/manual/switch-archive/)、[克隆](https://www.playcreator.cn/docs/flexi-archive/manual/clone-archive/)、[删除](https://www.playcreator.cn/docs/flexi-archive/manual/del-archive/)存档。 ### 2.支持任何复杂类型或自定义类型   Flexi Archive System 支持轻松添加新的数据类型和存档策略,允许你存档自定义的复杂类型数据。   目前系统已支持的类型: | ----- | ----- | ----- | |:----------:|:-------:|:-------:| | float | double | int | | long | bool | string | | vector2 | vector3 | vector4 | | object | list | array | | dictionary | custom | ····· |   如果你需要存档一个自定义类型,你无需关心存档过程中所做的操作,也无需对系统进行修改。你只需负责创建一个 CustomData 以及一个 AbstractDataType 具体类型,按照Litjson0.19所支持的类型要求对复杂的数据进行转换。 [具体见LitJson文档](https://litjson.net/blog/2023/11/litjson-v0.19.0-released)   建议你在编写 Wrapper 的同时对 ToString 方法进行重写,方便数据以明文的形式显示在开发环境中。 代码示例(Plan A): ```C# /// /// 1.create construct method /// public class CustomDataType : AbstractDataType { public CustomDataType(string dataStr) : base(dataStr){} } /// /// 2.override "ToString(CustomData)" function if would know detail data /// public class CustomData { public string author = "温文"; public int code = 1; public double luckly = 1.0f; public override string ToString() { return "author: " + author + " code: " + code + " luckly: " + luckly; } } ``` 代码示例(Plan B): 见文章 [创建自定义数据类型 - Flexi Archive](https://www.playcreator.cn/docs/flexi-archive/manual/create-custom-data/) ### 3.对象字段与数据绑定   除了持有DataObject操作存档之外,Flexi Archive 还提供了对象字段与数据绑定方案。你可以将存档数据与对象的属性进行绑定。这意味着,你对字段成员的访问与赋值,等同于对存档数据的读写。   这一绑定机制简化了数据管理的流程,无需你手动编写过程代码来处理数据的读写操作,极大地简化了存档流程。   见文档 : [对象字段与数据绑定 - 简化存档流程](https://www.playcreator.cn/docs/flexi-archive/manual/properties-bind-data/) ### 4.支持多种序列化方式   支持 File、PlayerPrefs、SQL-DB 异步序列化(存档/读档)方式。你可以根据项目模块需求以及性能考量,自由决定该模块存档系统所使用的序列化方式,默认为 SQL-DB 方式。   多存档支持: 1. File方式:支持多存档 2. PlayerPrefs方式:出于性能考虑,暂不支持多存档 3. SQL-DB方式:支持多存档   分析: 1. File方式(JSON):适用于存档量需求适中的项目,方便用于云存档上传。 2. PlayerPrefs方式:适用于单个数据量小且每组存档量少的存档,访问较快。如记录下用户某个操作、用户本地所做的设置等。 3. SQL-DB方式:适用于存档量需求较大的项目,读取开销与压缩比相比File方式在大多情况下要低。 ### 5.保存点存档   你需要在合适的时机,触发存档操作。否则你对数据的修改,只会使 Memory 的数据发生变化。   值得一提的是,Flexi Archive System 只会对发生变化的数据进行异步存档。 ```C# archiveManager.SaveAsync(() => { Debug.Log("async save successfully");}); ```   见文档:[保存存档](https://www.playcreator.cn/docs/flexi-archive/manual/save-archive/) ### 6.分组策略   Flexi Archive System 使用 GroupKey + DataKey 的分组策略,你可以根据你的业务来对数据进行分组。   合理的分组有助于降低存档的开销。   我给出的最理想情况:将经常在同一时间内发生变化的数据划分为一组。 ### 7.支持同一设备下多账号存档共存   在用户登录成功后设置 USER_KEY 即可。若你的程序无登录业务,你可以不用设置。 示例: ``` C# void Into() { DataArchiveConstData.USER_KEY = "Wenen"; } ``` ### 8.支持创建多个存档系统   你可以根据程序模块的不同,自由的创建多个不同的存档系统。 见文档:[创建存档系统](https://www.playcreator.cn/docs/flexi-archive/manual/create-archive-system/)   方便你根据具体的模块来定制扩展存档系统,也可以选择更适合该模块的序列化存档方式。 ### 9.数据存档监视工具   Flexi Archive System 提供了与系统层配套的数据查询工具,方便你在运行时实时的监视数据的变化(支持非运行时和运行时使用)。 ![img](https://github.com/wenen-creator/FlexiArchiveSystem/blob/dev/Misc/img/preview02.PNG) ### 10.性能   Flexi Archive System 系统内部采用了高效的存储机制。默认采用按需载入原则,通过异步IO、缓存机制、分组策略、脏标记等大量优化策略,确保在进行大量频繁的数据操作时,也能够快速响应,尽可能的避免复杂情况下帧率波动等性能问题。 ## 关于作者 author: 温文 blog: https://www.playcreator.cn email: yixiangluntan@163.com ================================================ FILE: System/Assist/ArchiveManagerRegister.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Collections.Generic; using FlexiArchiveSystem.Setting; using UnityEngine; namespace FlexiArchiveSystem.Assist { public class ArchiveManagerRegister { public static ArchiveManagerRegister instance = new ArchiveManagerRegister(); private Dictionary ArchiveMgrMap = new Dictionary(); public void Register(IFlexiDataArchiveManager mgr) { string ModuleName = mgr.ArchiveSetting.ModuleName; if (string.IsNullOrEmpty(ModuleName)) { Logger.LOG_ERROR("The ModuleName of the archive system cannot be empty"); return; } if (ArchiveMgrMap.ContainsKey(ModuleName) && Application.isPlaying) { Logger.LOG_WARNING($"ModuleName:{ModuleName} re-registered。An archive system named {mgr.GetType().Name} has been registered"); } ArchiveMgrMap[ModuleName] = mgr; } public void RemoveRegister(IFlexiDataArchiveManager mgr) { string ModuleName = mgr.ArchiveSetting.ModuleName; if (ArchiveMgrMap.ContainsKey(ModuleName) == false) { return; } ArchiveMgrMap.Remove(ModuleName); } public IFlexiDataArchiveManager FindByArchiveSetting(IArchiveSetting archiveSetting) { return FindByArchiveSetting(archiveSetting.ModuleName); } public IFlexiDataArchiveManager FindByArchiveSetting(string moduleName) { ArchiveMgrMap.TryGetValue(moduleName, out var mgr); return mgr; } } } ================================================ FILE: System/Assist/ArchiveManagerRegister.cs.meta ================================================ fileFormatVersion: 2 guid: fab2434bcfb04ee88f171620ce8540d5 timeCreated: 1724310577 ================================================ FILE: System/Assist/DataTypeRegister.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; namespace FlexiArchiveSystem { public class DataTypeBinder { //{valueWrapperMeta : dataTypeMeta} public static Dictionary binder; /// /// bind value and AbstractDataTypeWrapper /// /// AbstractDataTypeWrapper /// Type of value public static void Register(Type dataTypeMeta, Type valueTypeMeta) { if (binder == null) { binder = new Dictionary(); } binder[valueTypeMeta] = dataTypeMeta; } /// /// need to register the binding first /// /// /// public static Type GetByValueType() { Type valueTypeMeta = typeof(T); if (binder.TryGetValue(valueTypeMeta, out var dataTypeMeta)) { return dataTypeMeta; } return null; } } } ================================================ FILE: System/Assist/DataTypeRegister.cs.meta ================================================ fileFormatVersion: 2 guid: acaed9ecbeb24f3699a3c30205e24bc4 timeCreated: 1728726071 ================================================ FILE: System/Assist/Info/DataArchiveConstData.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.IO; namespace FlexiArchiveSystem { public static partial class DataArchiveConstData { private static string AUTHOR { get; set; } = "温文"; public static string USER_KEY { get; set; } = "Wenen"; public const string Prefix_ArchiveIDKey = "ArchiveID"; private const string ArchiveExtensionName = "bin"; private const string SaveAllGroupKeyFileName = "group"; private static string _ArchiveRootDirectoryPath; private static string ArchiveRootDirectoryPath { get { if (string.IsNullOrEmpty(_ArchiveRootDirectoryPath)) { _ArchiveRootDirectoryPath = Path.Combine(AppPersistentDataPath, "tmp"); } return _ArchiveRootDirectoryPath; } } private static string _UserArchiveDirectoryPath; public static string UserArchiveDirectoryPath { get { if (string.IsNullOrEmpty(_UserArchiveDirectoryPath)) { _UserArchiveDirectoryPath = Path.Combine(ArchiveRootDirectoryPath, USER_KEY); } return _UserArchiveDirectoryPath; } } public static string GetUserCertainArchiveSystemDirectoryPath(string MoudleName) { return Path.Combine(UserArchiveDirectoryPath, MoudleName); } public static string GetAndCombineDataFilePath(string path, string groupKey) { string fileName = groupKey; if (string.IsNullOrEmpty(ArchiveExtensionName) == false) { fileName = string.Format("{0}.{1}",fileName, ArchiveExtensionName); } string groupFilePath = Path.Combine(path, fileName); return groupFilePath; } public static int DefaultStartArchiveID = 0; public static string GetArchiveKey(int archiveID) { return string.Format("{0}{1}", Prefix_ArchiveIDKey, archiveID); } public static string GetArchiveDirectoryPath(string ModuleName, int archiveID) { return Path.Combine(GetUserCertainArchiveSystemDirectoryPath(ModuleName), GetArchiveKey(archiveID)); } public static string GetArchiveSystemInfoDirectoryPath(string ModuleName, int archiveID) { return Path.Combine(GetUserCertainArchiveSystemDirectoryPath(ModuleName), GetArchiveKey(archiveID), "DataTypeSystemInfo"); } public static string GetArchiveGroupKeysFilePath(string ModuleName, int archiveID) { return Path.Combine(GetArchiveDirectoryPath(ModuleName, archiveID), SaveAllGroupKeyFileName); } public static string GetGroupKeyInPlayerPrefs(string groupKey) { return string.Format($"{USER_KEY}_{groupKey}"); } public static string GetPrefsKey_CUR_ARCHIVE(string moduleName) { return USER_KEY + moduleName +"CurArchID"; } } } ================================================ FILE: System/Assist/Info/DataArchiveConstData.cs.meta ================================================ fileFormatVersion: 2 guid: b913fb441cf24ec6adc9e9fa4dccbf4c timeCreated: 1723621486 ================================================ FILE: System/Assist/Info/DataKeyHandler.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.IO; namespace FlexiArchiveSystem { public class DataKeyHandler { public static Tuple GetAndProcessKeyCollection(string key) { //spilt group and data key string[] keys = key.Split(Path.DirectorySeparatorChar); string groupKey = keys[0]; string dataKey = keys[1]; if (string.IsNullOrEmpty(dataKey)) { throw new InvalidDataException("Archiving accident! The Key of the data is invalid."); } if (string.IsNullOrEmpty(groupKey)) { groupKey = "Global"; } return new Tuple(groupKey, dataKey); } public static string CombieGroupAndDataKey(string groupKey, string dataKey) { return Path.Combine(groupKey, dataKey); } } } ================================================ FILE: System/Assist/Info/DataKeyHandler.cs.meta ================================================ fileFormatVersion: 2 guid: 2655168a07b948cbb207dd5a02cfbfe5 timeCreated: 1722250588 ================================================ FILE: System/Assist/Info.meta ================================================ fileFormatVersion: 2 guid: 66cefa3c99314ceebd99aca99e7f9a0f timeCreated: 1724293007 ================================================ FILE: System/Assist/Logger.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem.Assist { /// /// Please go to Unity-Logger what is core code; /// public static partial class Logger { } } ================================================ FILE: System/Assist/Logger.cs.meta ================================================ fileFormatVersion: 2 guid: 156d93088b7a41729feda7cf3f30cc2c timeCreated: 1724305736 ================================================ FILE: System/Assist.meta ================================================ fileFormatVersion: 2 guid: 40880963337c4219866068507213f953 timeCreated: 1724305727 ================================================ FILE: System/Attributes/FlexiArchiveAttribute.cs ================================================ using System; namespace FlexiArchiveSystem.Attributes { [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class FlexiDataBinderAttribute : Attribute { public string GroupKey; public string SubKey; public FlexiDataBinderAttribute(string GroupKey, string SubKey) { this.GroupKey = GroupKey; this.SubKey = SubKey; } } [AttributeUsage(AttributeTargets.Class)] public class UsageFlexiDataContainerAttribute : Attribute { public UsageFlexiDataContainerAttribute() { } } } ================================================ FILE: System/Attributes/FlexiArchiveAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: b276d4cda59f4cac82d68a0413c90ad8 timeCreated: 1728733968 ================================================ FILE: System/Attributes.meta ================================================ fileFormatVersion: 2 guid: 9863880458fa4d468fd4061befd57708 timeCreated: 1728733938 ================================================ FILE: System/Base/DataGroup.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FlexiArchiveSystem.Assist; using FlexiArchiveSystem.Setting; namespace FlexiArchiveSystem { public class DataGroup : IDisposable { public Dictionary dataObjectMap = new Dictionary(); private List dirtyDataObjectKeys = new List(); private string _groupKey; public event Action OnDirtyHandler; private IArchiveSetting _ArchiveSetting; public DataGroup(string groupKey) { _groupKey = groupKey; } internal void InjectArchiveSetting(IArchiveSetting setting) { _ArchiveSetting = setting; } public void LoadAll() { } public bool TryGetDataObject(string key, out DataObject dataObject) { dataObject = GetDataObject(key); return dataObject != null; } public DataObject GetDataObject(string key) { string fullKey = DataKeyHandler.CombieGroupAndDataKey(_groupKey, key); DataObject dataObject = GetCacheDataObject(fullKey); if (dataObject == null) { dataObject = CreateNewDataObject(fullKey); dataObjectMap.Add(fullKey, dataObject); } return dataObject; } private DataObject GetCacheDataObject(string key) { dataObjectMap.TryGetValue(key, out DataObject dataObject); return dataObject; } private DataObject CreateNewDataObject(string key) { DataObject dataObject = new DataObject(key); dataObject.OnDirtyHandler += DataObjectHappenDirty; dataObject.InjectArchiveSetting(_ArchiveSetting); dataObject.Init(); return dataObject; } private void DataObjectHappenDirty(string key) { if (dirtyDataObjectKeys.Contains(key) == false) { dirtyDataObjectKeys.Add(key); } OnDirtyHandler?.Invoke(_groupKey); } public void Delete() { _ArchiveSetting.DataArchiveOperation.DeleteGroup(_groupKey); _ArchiveSetting.DataTypeSystemInfoOperation.DeleteGroup(_groupKey); } public void Save() { if (dirtyDataObjectKeys.Count == 0) { return; } var dirtyDataObjectList = dirtyDataObjectKeys.Select(GetCacheDataObject).ToArray(); _ArchiveSetting.DataArchiveOperation.DataPersistent(dirtyDataObjectList); foreach (var dirtyDataObject in dirtyDataObjectList) { dirtyDataObject._dataType.Refresh(); dirtyDataObject.TryToSaveDataSystemInfo(); dirtyDataObject.CleanDirty(); } if (_ArchiveSetting.IsLog) { Logger.LOG($"Data archive update | Group: [{_groupKey}] - [{dirtyDataObjectKeys.Count}]"); } dirtyDataObjectKeys.Clear(); } public async Task SaveAsync(Action complete = null) { if (dirtyDataObjectKeys.Count == 0) { return; } //TODO : cancel token var dirtyDataObjectList = dirtyDataObjectKeys.Select(GetCacheDataObject).ToArray(); await _ArchiveSetting.DataArchiveOperation.DataPersistentAsync(complete, dirtyDataObjectList); foreach (var dirtyDataObject in dirtyDataObjectList) { dirtyDataObject._dataType.Refresh(); dirtyDataObject.CleanDirty(); } TryToSaveSystemInfo(null, dirtyDataObjectList); complete?.Invoke(); if (_ArchiveSetting.IsLog) { Logger.LOG($"Data archive update | Group: [{_groupKey}] - [{dirtyDataObjectKeys.Count}]"); } dirtyDataObjectKeys.Clear(); } private void TryToSaveSystemInfo(Action complete, params DataObject[] dataObjects) { #if UNITY_EDITOR _ArchiveSetting.DataTypeSystemInfoOperation.DataPersistentAsync(complete, dataObjects); #else if (_ArchiveSetting.IsAllowSaveDataSystemInfoInPlayerDevice) { _ArchiveSetting.DataTypeSystemInfoOperation.DataPersistentAsync(complete, dataObjects); } #endif } public void Dispose() { if (dataObjectMap != null) { foreach (var pair in dataObjectMap) { pair.Value.Dispose(); } dataObjectMap.Clear(); dataObjectMap = null; } dirtyDataObjectKeys = null; _groupKey = null; OnDirtyHandler = null; } } } ================================================ FILE: System/Base/DataGroup.cs.meta ================================================ fileFormatVersion: 2 guid: be3a0404d35f45c4954c38434177ec0f timeCreated: 1722063915 ================================================ FILE: System/Base/DataObject.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Threading.Tasks; using FlexiArchiveSystem.ArchiveOperation; using FlexiArchiveSystem.Setting; namespace FlexiArchiveSystem { public class DataObject : IDisposable { private string _Key; private string _data; public IDataType _dataType; public event Action OnDirtyHandler; public event Action OnPersistentHandler; private IArchiveSetting _ArchiveSetting; public bool isDirty { get; protected set; } private bool isAsyncSave; private Action aysncSaveComplete; private Task aysncSaveTask; private string serializeData; public string Key { get => _Key; private set => _Key = value; } private IDataArchiveOperation ArchiveOperation => _ArchiveSetting.DataArchiveOperation; public DataObject(string key) { _Key = key; } public void Init() { _data = LoadFromDiskTo(); } private string LoadFromDiskTo() { var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(_Key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; return ArchiveOperation.Read(groupKey, dataKey); } internal void InjectArchiveSetting(IArchiveSetting setting) { _ArchiveSetting = setting; } public T GetData() where T : IDataType { if (_dataType != null) { return (T)_dataType; } return CreateDataType(); } /// /// Get an IDataType instance based on the DataType type. /// 根据DataType的类型来取得IDataType实例。 /// /// /// public IDataType GetData(Type dataTypeMeta) { if (_dataType != null) { return (IDataType)_dataType; } // CreateDataType var concreteDataType = (IDataType)Activator.CreateInstance(dataTypeMeta, _data); _dataType = concreteDataType; concreteDataType.OnDirtyHandler += SetDirty; concreteDataType.InjectArchiveOperationType(_ArchiveSetting.ArchiveOperationMode); return concreteDataType; } private T CreateDataType() where T : IDataType { var concreteDataType = ConvertTo(_data); _dataType = concreteDataType; concreteDataType.OnDirtyHandler += SetDirty; concreteDataType.InjectArchiveOperationType(_ArchiveSetting.ArchiveOperationMode); return concreteDataType; } private T ConvertTo(string dataStr) where T : IDataType { Type[] types = new Type[] { typeof(int) }; var concreteDataType = (T)Activator.CreateInstance(typeof(T), dataStr); return concreteDataType; } private void SetDirty() { OnDirtyHandler?.Invoke(_Key); isDirty = true; } public void CleanDirty() { isDirty = false; } private void OnDataPersistent(string dataStr, DataTypeSystemInfo dataTypeSystemInfo) { isDirty = false; var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(_Key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; if (isAsyncSave) { var temp = aysncSaveComplete; aysncSaveTask = ArchiveOperation.DataPersistentAsync(groupKey, dataKey, dataStr, () => { temp?.Invoke(); TryToSaveDataSystemInfo(groupKey, dataKey, dataTypeSystemInfo); //TODO : Immediately or wait for the task to complete (立刻执行还是等待任务完成) OnPersistentHandler?.Invoke(_Key); }); } else { ArchiveOperation.DataPersistent(groupKey, dataKey, dataStr); TryToSaveDataSystemInfo(groupKey, dataKey, dataTypeSystemInfo); OnPersistentHandler?.Invoke(_Key); } aysncSaveComplete = null; } private void TryToSaveDataSystemInfo(string groupKey, string dataKey, DataTypeSystemInfo dataTypeSystemInfo) { #if UNITY_EDITOR _ArchiveSetting.DataTypeSystemInfoOperation.ToAsyncSaveDataTypeSystemInfo(groupKey, dataKey, dataTypeSystemInfo); #else if (_ArchiveSetting.IsAllowSaveDataSystemInfoInPlayerDevice) { _ArchiveSetting.DataTypeSystemInfoOperation.ToAsyncSaveDataTypeSystemInfo(groupKey, dataKey, dataTypeSystemInfo); } #endif } public void TryToSaveDataSystemInfo() { var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(_Key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; TryToSaveDataSystemInfo(groupKey, dataKey, _dataType.SystemInfo); } public void Save() { if (isDirty) { isAsyncSave = false; OnDataPersistent(GetSerializeData(), _dataType.SystemInfo); _dataType.Refresh(); } } public async Task SaveAsync(Action complete = null) { if (isDirty) { isAsyncSave = true; aysncSaveComplete = complete; OnDataPersistent(GetSerializeData(), _dataType.SystemInfo); if (aysncSaveTask != null) { await aysncSaveTask; } _dataType.Refresh(); } } internal string GetSerializeData() { if (isDirty) { serializeData = _dataType.Serialize(); } return serializeData; } public void Delete() { var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(_Key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; ArchiveOperation.Delete(groupKey, dataKey); _ArchiveSetting.DataTypeSystemInfoOperation.Delete(groupKey, dataKey); _dataType.Reset(); } public void Dispose() { _Key = null; _data = null; _dataType = null; OnDirtyHandler = null; OnPersistentHandler = null; } } } ================================================ FILE: System/Base/DataObject.cs.meta ================================================ fileFormatVersion: 2 guid: 74c0946bcee247c78b5784cbe5e85024 timeCreated: 1722063834 ================================================ FILE: System/Base/DataTypeSystemInfo.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using LitJson; namespace FlexiArchiveSystem { public struct DataTypeSystemInfo { public string systemType; //DataType的System.Type public DataTypeSystemInfo(string type) { this.systemType = type; } public string Serialize() { return JsonMapper.ToJson(this); } } } ================================================ FILE: System/Base/DataTypeSystemInfo.cs.meta ================================================ fileFormatVersion: 2 guid: 764c02226a174ab6a5b15089b007d83c timeCreated: 1723089773 ================================================ FILE: System/Base/FlexiArchiveSystemInfo.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; namespace FlexiArchiveSystem { public struct FlexiArchiveSystemInfo { public DateTime Create_Time; } } ================================================ FILE: System/Base/FlexiArchiveSystemInfo.cs.meta ================================================ fileFormatVersion: 2 guid: 0b00c8a8e5d548c09f8614283f4c50c6 timeCreated: 1725610693 ================================================ FILE: System/Base/IDataType.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Reflection; namespace FlexiArchiveSystem { public interface IDataType { public event Action OnDirtyHandler; public DataTypeSystemInfo SystemInfo { get; } public MethodInfo GetWriteDataMethodInfo(); public void WriteByGenericObject(object genericValue); public void Refresh(); public string Serialize(); public void Reset(); public string ToString(); public void InjectArchiveOperationType(ArchiveOperationType archiveOperationType); } } ================================================ FILE: System/Base/IDataType.cs.meta ================================================ fileFormatVersion: 2 guid: b6a57028ac0944d085c83580b11981ed timeCreated: 1722065200 ================================================ FILE: System/Base.meta ================================================ fileFormatVersion: 2 guid: d69a15d4166d4e61b6448ddabcf629a2 timeCreated: 1722063824 ================================================ FILE: System/DataArchiveOperation/CloneSource/DataArchiveSourceWrapper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Collections.Generic; using LitJson; namespace FlexiArchiveSystem.ArchiveOperation { public class IDataArchiveSourceWrapper { } public class DictionaryJsonArchiveSourceWrapper : IDataArchiveSourceWrapper { public Dictionary source; } public class SqliteArchiveSourceWrapper : IDataArchiveSourceWrapper { public string sourcePath; } } ================================================ FILE: System/DataArchiveOperation/CloneSource/DataArchiveSourceWrapper.cs.meta ================================================ fileFormatVersion: 2 guid: c4380753f0264d1db6cb88ccba92f38b timeCreated: 1723807892 ================================================ FILE: System/DataArchiveOperation/CloneSource.meta ================================================ fileFormatVersion: 2 guid: 54ee9e5614d64e258670812444f91064 timeCreated: 1723808096 ================================================ FILE: System/DataArchiveOperation/FileModeDataArchiveOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using LitJson; namespace FlexiArchiveSystem.ArchiveOperation { /// /// 文件全量形式的存档方式 /// public class FileModeDataArchiveOperation : IDataArchiveOperation, ISetDataArchivePath, ICloneDataArchive { private string _ArchiveSystemName; public string ArchiveSystemName => _ArchiveSystemName; public bool IsValidation { get { return IsActive && Directory.Exists(Path); } } private bool IsActive; public string Path { get; set; } private string FilePath; protected Dictionary groupDataMap; public List AllGroupKeys; private int _archiveID; private DataArchiveOperationHelper archiveOperationHelper; public DataArchiveOperationHelper ArchiveOperationHelper { get { if (archiveOperationHelper == null) { SetDataArchiveOperationHelper(DataArchiveOperationFactory.GetDataArchiveOperationHelper()); } return archiveOperationHelper; } } private Dictionary WriteCancellationTokenSourceMap; public void SetDataArchiveOperationHelper(DataArchiveOperationHelper helper) { helper.Init(ArchiveSystemName); helper.UpdateDirtyState(_archiveID); archiveOperationHelper = helper; } public void Init(string moudleName,int archiveID) { _ArchiveSystemName = moudleName; SetArchiveID(archiveID); groupDataMap = new Dictionary(); IsActive = true; WriteCancellationTokenSourceMap = new Dictionary(); } public void SetArchiveID(int archiveID) { _archiveID = archiveID; } protected bool DataPersistentReadyWork(string groupKey,string dataKey, string dataStr) { if (Directory.Exists(Path) == false) { Directory.CreateDirectory(Path); } bool hasExistedBefore = TryGetJsonData(groupKey, out JsonData jsonData); if (hasExistedBefore == false) { jsonData = new JsonData(); groupDataMap.Add(groupKey, jsonData); } jsonData[dataKey] = JsonMapper.ToObject(dataStr); return hasExistedBefore; } private void WriteToDisk(string filePath, string text) { File.WriteAllText(filePath, text); } protected async Task WriteToDiskAsync(string filePath, string text) { //char stream WriteCancellationTokenSourceMap.TryGetValue(filePath, out var cancelTokenSource); if (cancelTokenSource != null) { cancelTokenSource.Cancel(); cancelTokenSource.Dispose(); } using (var sourceStream = new StreamWriter(filePath)) { sourceStream.AutoFlush = false; ReadOnlyMemory readOnlyMemory = new ReadOnlyMemory(text.ToCharArray()); cancelTokenSource = CreateCancelTokenSource(filePath); await sourceStream.WriteAsync(readOnlyMemory, cancelTokenSource.Token); await sourceStream.FlushAsync(); cancelTokenSource.Dispose(); WriteCancellationTokenSourceMap.Remove(filePath); } } public void DataPersistent(string groupKey, string dataKey, string dataStr) { bool hasExistedBefore = DataPersistentReadyWork(groupKey, dataKey, dataStr); string groupFilePath = GetAndCombineDataFilePath(groupKey); WriteToDisk(groupFilePath, groupDataMap[groupKey].ToJson()); bool isRewriteGroupKeys = hasExistedBefore == false; if (isRewriteGroupKeys) { TryRecordKey(groupKey); } } public void DataPersistent(params DataObject[] dataObjects) { if (dataObjects.Length == 0) { return; } HashSet hashSet = new HashSet(); foreach (var dataObject in dataObjects) { string key = dataObject.Key; var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; bool hasExistedBefore = DataPersistentReadyWork(groupKey, dataKey, dataObject.GetSerializeData()); bool isRewriteGroupKeys = hasExistedBefore == false; if (isRewriteGroupKeys) { TryRecordKey(groupKey); } hashSet.Add(groupKey); } foreach (var groupKey in hashSet) { string groupFilePath = GetAndCombineDataFilePath(groupKey); WriteToDisk(groupFilePath, groupDataMap[groupKey].ToJson()); } } public async Task DataPersistentAsync(string groupKey, string dataKey, string dataStr, Action complete) { bool hasExistedBefore = DataPersistentReadyWork(groupKey, dataKey, dataStr); string groupFilePath = GetAndCombineDataFilePath(groupKey); await WriteToDiskAsync(groupFilePath, groupDataMap[groupKey].ToJson()); bool isRewriteGroupKeys = hasExistedBefore == false; if (isRewriteGroupKeys) { TryRecordKey(groupKey); } complete?.Invoke(); } public virtual async Task DataPersistentAsync(Action complete, params DataObject[] dataObjects) { if (dataObjects.Length == 0) { return; } HashSet hashSet = new HashSet(); foreach (var dataObject in dataObjects) { string key = dataObject.Key; var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; bool hasExistedBefore = DataPersistentReadyWork(groupKey, dataKey, dataObject.GetSerializeData()); bool isRewriteGroupKeys = hasExistedBefore == false; if (isRewriteGroupKeys) { TryRecordKey(groupKey); } hashSet.Add(groupKey); } IList writeTasks = new List(); foreach (var groupKey in hashSet) { string groupFilePath = GetAndCombineDataFilePath(groupKey); writeTasks.Add(WriteToDiskAsync(groupFilePath, groupDataMap[groupKey].ToJson())); } await Task.WhenAll(writeTasks); complete?.Invoke(); } public virtual void TryRecordKey(string groupKey) { if (AllGroupKeys != null) { AllGroupKeys.Add(groupKey); } ArchiveOperationHelper.RecordKey(_archiveID, groupKey); } public string Read(string groupKey, string dataKey) { if (Directory.Exists(Path) == false) { return ""; } TryGetJsonData(groupKey, out JsonData jsonData); string jsonResult = ""; try { if (jsonData != null) { JsonData concreteData_JsonData = jsonData[dataKey]; jsonResult = concreteData_JsonData == null ? "" : concreteData_JsonData.ToJson(); } } catch (KeyNotFoundException) { jsonResult = ""; } return jsonResult; } #pragma warning disable CS1998 public virtual async Task DeleteAll() { if (Directory.Exists(DataArchiveConstData.GetArchiveDirectoryPath(ArchiveSystemName, _archiveID))) { Directory.Delete(DataArchiveConstData.GetArchiveDirectoryPath(ArchiveSystemName, _archiveID), true); } TryRemoveAllGroupKey(); this.Dispose(); } #pragma warning restore CS1998 public virtual void TryRemoveAllGroupKey() { ArchiveOperationHelper.DeleteAllGroupKeyFromDisk(); } public void Delete(string groupKey, string dataKey) { bool isGet = TryGetJsonData(groupKey, out JsonData jsonData); if (isGet == false) { return; } jsonData[dataKey] = null; string groupFilePath = GetAndCombineDataFilePath(groupKey); File.WriteAllText(groupFilePath, jsonData.ToJson()); } public void DeleteGroup(string groupKey) { string groupFilePath = GetAndCombineDataFilePath(groupKey); if (File.Exists(groupFilePath)) { File.Delete(groupFilePath); ArchiveOperationHelper.RemoveGroupKey(groupKey); } } private bool TryGetJsonData(string groupKey, out JsonData jsonData) { jsonData = null; if (groupDataMap.TryGetValue(groupKey, out jsonData) == false) { string str = LoadFromDisk(groupKey); if (string.IsNullOrEmpty(str)) { return false; } jsonData = JsonMapper.ToObject(str); groupDataMap.Add(groupKey, jsonData); } return true; } private async Task<(bool,JsonData)> TryGetJsonDataAsync(string groupKey) { JsonData jsonData = null; if (groupDataMap.TryGetValue(groupKey, out jsonData) == false) { string str = await LoadFromDiskAsync(groupKey); if (string.IsNullOrEmpty(str)) { return (false, null); } jsonData = JsonMapper.ToObject(str); groupDataMap.Add(groupKey, jsonData); } return (true, jsonData); } private string LoadFromDisk(string groupKey) { string filePath = GetAndCombineDataFilePath(groupKey); if (File.Exists(filePath) == false) { return ""; } string str = File.ReadAllText(filePath, Encoding.UTF8); return str; } private async Task LoadFromDiskAsync(string groupKey) { string filePath = GetAndCombineDataFilePath(groupKey); if (File.Exists(filePath) == false) { return ""; } var sb = new StringBuilder(); using (var sourceStream = new StreamReader(filePath)) { char[] buffer = new char[50]; int readLen; while ((readLen = await sourceStream.ReadAsync(buffer, 0,buffer.Length)) != 0) { sb.Append(buffer, 0, readLen); } } return sb.ToString(); } private async Task> LoadAllGroupKeyFromDisk() { return await ArchiveOperationHelper.GetAllGroupKey(); } protected string GetAndCombineDataFilePath(string groupKey) { string groupFilePath = DataArchiveConstData.GetAndCombineDataFilePath(Path, groupKey); return groupFilePath; } public Dictionary ConvertToDictionary(string groupKey) { string groupFilePath = GetAndCombineDataFilePath(groupKey); TryGetJsonData(groupKey, out JsonData jsonData); return JsonMapper.ToObject>(jsonData.ToJson()); } public async Task GetSource() { if (AllGroupKeys == null) { AllGroupKeys = await LoadAllGroupKeyFromDisk(); } var sourceWrapper = new DictionaryJsonArchiveSourceWrapper(); if (AllGroupKeys != null) { List readTasks = new List(); foreach (var groupKey in AllGroupKeys) { readTasks.Add(TryGetJsonDataAsync(groupKey)); } await Task.WhenAll(readTasks); sourceWrapper.source = groupDataMap; } else { sourceWrapper.source = null; } return sourceWrapper; } public async Task CloneTo(IDataArchiveSourceWrapper source) { if (source is DictionaryJsonArchiveSourceWrapper == false) { throw new Exception("clone source error"); } var jsonSource = source as DictionaryJsonArchiveSourceWrapper; groupDataMap = jsonSource.source; if (groupDataMap == null || groupDataMap.Count == 0) { return; } if (Directory.Exists(Path) == false) { Directory.CreateDirectory(Path); } List writeTasks = new List(); foreach (var pair in groupDataMap) { string groupKey = pair.Key; string filePath = GetAndCombineDataFilePath(groupKey); writeTasks.Add(WriteToDiskAsync(filePath, pair.Value.ToJson())); } await Task.WhenAll(writeTasks); RecordAllGroupKeys(); } protected virtual void RecordAllGroupKeys() { ArchiveOperationHelper.RecordAllGroupKeyWhenClone(_archiveID); } private CancellationTokenSource CreateCancelTokenSource(string filePath) { var source = new CancellationTokenSource(); WriteCancellationTokenSourceMap[filePath] = source; return source; } public void Dispose() { groupDataMap = null; AllGroupKeys = null; archiveOperationHelper = null; IsActive = false; GC.Collect(); GC.WaitForPendingFinalizers(); } public async Task DisposeAsync() { Dispose(); } } } ================================================ FILE: System/DataArchiveOperation/FileModeDataArchiveOperation.cs.meta ================================================ fileFormatVersion: 2 guid: 39ace13684ee43ef86c51ac82f4b65fb timeCreated: 1722233810 ================================================ FILE: System/DataArchiveOperation/Getter/DataArchiveOperationFactory.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; namespace FlexiArchiveSystem.ArchiveOperation { internal static class DataArchiveOperationFactory { public static IDataArchiveOperation CreateArchiveOperationObject(ArchiveOperationType operationType, string moduleName ,int archiveID) { IDataArchiveOperation dataArchiveOperation; switch (operationType) { case ArchiveOperationType.FileMode: var fileModeDataArchiveOperation = new FileModeDataArchiveOperation(); dataArchiveOperation = fileModeDataArchiveOperation; break; case ArchiveOperationType.PlayerPrefs: dataArchiveOperation = new PlayerPrefsDataArchiveOperation(); break; case ArchiveOperationType.Sqlite: var sqliteDataArchiveOperation = new SQLDataArchiveOperation(true); dataArchiveOperation = sqliteDataArchiveOperation; break; default: throw new ArgumentOutOfRangeException(nameof(operationType), operationType, null); } bool needSetPath = dataArchiveOperation is ISetDataArchivePath; if (needSetPath) { ISetDataArchivePath iSetDataArchivePath = dataArchiveOperation as ISetDataArchivePath; iSetDataArchivePath.Path = DataArchiveConstData.GetArchiveDirectoryPath(moduleName, archiveID); } return dataArchiveOperation; } public static DataSystemInfoArchiveOperation CreateArchiveSystemInfoOperationObject( ArchiveOperationType operationType,string moduleName, int archiveID) { var DataTypeSystemInfoOperation = new DataSystemInfoArchiveOperation(); if (DataTypeSystemInfoOperation is ISetDataArchivePath) { DataTypeSystemInfoOperation.SystemInfoPath = DataArchiveConstData.GetArchiveSystemInfoDirectoryPath(moduleName, archiveID); } return DataTypeSystemInfoOperation; } public static DataArchiveOperationHelper GetDataArchiveOperationHelper() { return new DataArchiveOperationHelper(); } } } ================================================ FILE: System/DataArchiveOperation/Getter/DataArchiveOperationFactory.cs.meta ================================================ fileFormatVersion: 2 guid: 4cf384420d054e2fbdbade909115fd11 timeCreated: 1723624740 ================================================ FILE: System/DataArchiveOperation/Getter.meta ================================================ fileFormatVersion: 2 guid: 8c87ce6fc79544aa90e7302524e05584 timeCreated: 1724293282 ================================================ FILE: System/DataArchiveOperation/IO/IOHelper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Threading.Tasks; using System.IO; namespace FlexiArchiveSystem.ArchiveOperation.IO { public class IOHelper { public static bool FileIsInUse(string filePath) { if (File.Exists(filePath) == false) { return false; } try { using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None)); } catch (IOException) { return true; } return false; } public static async Task FileIsInUse(string filePath, int timeout , int intervalCheckTime, bool isImmeQuery = false) { if (File.Exists(filePath) == false) { return false; } if (intervalCheckTime < 20 || intervalCheckTime >= timeout) { throw new Exception("The interval detection time is invalid"); } float time = 0; if (isImmeQuery == false) { time = intervalCheckTime; await Task.Delay(intervalCheckTime); } while (time < timeout) { try { using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None)); //No Use return false; } catch (IOException) { time += intervalCheckTime; if (time < timeout) { await Task.Delay(intervalCheckTime); } } } return true; } public static async void FileIsInUse(string filePath, int timeout , int intervalCheckTime,Action noUseAction, bool isImmeQuery = false) { if (intervalCheckTime < 20 || intervalCheckTime >= timeout) { throw new Exception("间隔检测时间无效"); } float time = 0; if (isImmeQuery == false) { time = intervalCheckTime; await Task.Delay(intervalCheckTime); } while (time < timeout) { try { using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None)); //No Use noUseAction?.Invoke(); } catch (IOException) { time += intervalCheckTime; if (time < timeout) { await Task.Delay(intervalCheckTime); } } } } } } ================================================ FILE: System/DataArchiveOperation/IO/IOHelper.cs.meta ================================================ fileFormatVersion: 2 guid: abcb2c5e6fc8444cb07d03337dba20a0 timeCreated: 1725516788 ================================================ FILE: System/DataArchiveOperation/IO.meta ================================================ fileFormatVersion: 2 guid: 6c36ea73d10242198686dab001250cd6 timeCreated: 1725516759 ================================================ FILE: System/DataArchiveOperation/Info/ArchiveOperationType.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem { public enum ArchiveOperationType { FileMode, PlayerPrefs, Sqlite } } ================================================ FILE: System/DataArchiveOperation/Info/ArchiveOperationType.cs.meta ================================================ fileFormatVersion: 2 guid: b61013a205534bbb94c1e55f4b537ea6 timeCreated: 1723606546 ================================================ FILE: System/DataArchiveOperation/Info.meta ================================================ fileFormatVersion: 2 guid: 33bfa063e4ed4d5b869294f1b2cde6bb timeCreated: 1724293032 ================================================ FILE: System/DataArchiveOperation/Interface/ICloneDataArchive.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Threading.Tasks; namespace FlexiArchiveSystem.ArchiveOperation { public interface ICloneDataArchive { public Task GetSource(); public Task CloneTo(IDataArchiveSourceWrapper source); } } ================================================ FILE: System/DataArchiveOperation/Interface/ICloneDataArchive.cs.meta ================================================ fileFormatVersion: 2 guid: 84ce0e2dc2dd441cbc4008b0ee7d98e1 timeCreated: 1723618583 ================================================ FILE: System/DataArchiveOperation/Interface/IDataArchiveOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Threading.Tasks; namespace FlexiArchiveSystem.ArchiveOperation { public interface IDataArchiveOperation : IDisposable { public string ArchiveSystemName { get; } public bool IsValidation { get; } public DataArchiveOperationHelper ArchiveOperationHelper { get; } public void SetDataArchiveOperationHelper(DataArchiveOperationHelper helper); public void Init(string moudleName,int archiveID); public void SetArchiveID(int archiveID); public void DataPersistent(string groupKey, string dataKey, string dataStr); public void DataPersistent(params DataObject[] dataObjects); public Task DataPersistentAsync(string groupKey, string dataKey, string dataStr, Action complete); public Task DataPersistentAsync(Action complete, params DataObject[] dataObjects); public string Read(string groupKey, string dataKey); public Task DeleteAll(); public void Delete(string groupKey, string dataKey); public void DeleteGroup(string groupKey); public Task DisposeAsync(); public void TryRecordKey(string groupKey); public void TryRemoveAllGroupKey(); } } ================================================ FILE: System/DataArchiveOperation/Interface/IDataArchiveOperation.cs.meta ================================================ fileFormatVersion: 2 guid: 4b831dcc86e04f3ca3fcbc717674e7e9 timeCreated: 1722232775 ================================================ FILE: System/DataArchiveOperation/Interface/ISetDataArchivePath.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem.ArchiveOperation { public interface ISetDataArchivePath { public string Path { get; set; } } } ================================================ FILE: System/DataArchiveOperation/Interface/ISetDataArchivePath.cs.meta ================================================ fileFormatVersion: 2 guid: 081216c470354c14a748b101ea4b7d03 timeCreated: 1722251068 ================================================ FILE: System/DataArchiveOperation/Interface.meta ================================================ fileFormatVersion: 2 guid: 9ea158a88ed847bf8390dff660983df2 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: System/DataArchiveOperation/PlayerPrefsDataArchiveOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem.ArchiveOperation { /// /// Please go to Unity-PlayerPrefsDataArchiveOperation what is core code; /// internal partial class PlayerPrefsDataArchiveOperation { } } ================================================ FILE: System/DataArchiveOperation/PlayerPrefsDataArchiveOperation.cs.meta ================================================ fileFormatVersion: 2 guid: 927bcc4f308441bc8349d9d5dc596faa timeCreated: 1724293396 ================================================ FILE: System/DataArchiveOperation/SQLDataArchiveOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Threading.Tasks; using FlexiArchiveSystem.ArchiveOperation.IO; using FlexiArchiveSystem.Assist; using FlexiArchiveSystem.Setting; using Mono.Data.Sqlite; namespace FlexiArchiveSystem.ArchiveOperation { internal class SQLDataArchiveOperation : IDataArchiveOperation, ISetDataArchivePath, ICloneDataArchive { private string _ArchiveSystemName; public string ArchiveSystemName => _ArchiveSystemName; public bool IsValidation { get { return IsActive && Directory.Exists(Path); } } private bool IsActive; private string FilePath; public string Path { get; set; } private DataArchiveOperationHelper archiveOperationHelper; public DataArchiveOperationHelper ArchiveOperationHelper { get { if (archiveOperationHelper == null) { SetDataArchiveOperationHelper(DataArchiveOperationFactory.GetDataArchiveOperationHelper()); } return archiveOperationHelper; } } private SqliteConnection connection; public List AllGroupKeys; public Dictionary> dataMap; private int _archiveID; public static bool IsUseConnectionPooling = false; public SQLDataArchiveOperation(bool isDelayInitializeDB = true) { if (isDelayInitializeDB == false) { InitDBConnection(); } } public void SetDataArchiveOperationHelper(DataArchiveOperationHelper helper) { helper.Init(ArchiveSystemName); helper.UpdateDirtyState(_archiveID); archiveOperationHelper = helper; } public void Init(string moudleName,int archiveID) { _ArchiveSystemName = moudleName; SetArchiveID(archiveID); dataMap = new Dictionary>(); FilePath = GetAndCombineDataFilePath(); IsActive = true; } public void SetArchiveID(int archiveID) { _archiveID = archiveID; } public void InitDBConnection() { if (Directory.Exists(Path) == false) { Directory.CreateDirectory(Path); } if (File.Exists(FilePath) == false) { SqliteConnection.CreateFile(FilePath); } string connectionString = string.Format("Data Source={0};Version={1};", FilePath, 3); if (IsUseConnectionPooling) { connectionString += "Pooling=true;"; } connection = new SqliteConnection(connectionString); connection.Open(); } public void DataPersistent(string groupKey, string dataKey, string dataStr) { if (connection == null) { InitDBConnection(); } int dataStrVarcharLen = dataStr.Length; string queryGroupTableCmd = $"select name from sqlite_master where type='table' and name='{groupKey}'"; SqliteCommand groupCommand = new SqliteCommand(queryGroupTableCmd, connection); var cmdReader = groupCommand.ExecuteReader(); bool exsitTable = cmdReader.Read(); if (exsitTable == false) { //create table string createTableCmd = $"create table {groupKey}(dataKey varchar({dataStrVarcharLen}) PRIMARY KEY,data varchar({dataStrVarcharLen}));"; SqliteCommand createTableCommand = new SqliteCommand(createTableCmd, connection); createTableCommand.ExecuteNonQuery(); } string updateDataCmd = $"INSERT OR REPLACE into {groupKey} (dataKey,data) values (@dataKey,@dataStr)"; SqliteCommand queryDataCommand = new SqliteCommand(updateDataCmd, connection); queryDataCommand.Parameters.AddWithValue("@dataKey",dataKey); queryDataCommand.Parameters.AddWithValue("@dataStr",dataStr); queryDataCommand.ExecuteNonQuery(); bool isExist = TryGetData(groupKey, dataKey, out string lastResult); if (isExist == false) { if (dataMap.ContainsKey(groupKey) == false) { dataMap.Add(groupKey, new Dictionary()); } } dataMap[groupKey][dataKey] = dataStr; bool hasExistedBefore = string.IsNullOrEmpty(lastResult) == false; if (hasExistedBefore == false) { TryRecordKey(groupKey); } } public void DataPersistent(params DataObject[] dataObjects) { foreach (var dataObject in dataObjects) { var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(dataObject.Key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; DataPersistent(groupKey, dataKey, dataObject.GetSerializeData()); } } public async Task DataPersistentAsync(string groupKey, string dataKey, string dataStr, Action complete) { if (connection == null) { InitDBConnection(); } int dataStrVarcharLen = dataStr.Length; string queryGroupTableCmd = $"select name from sqlite_master where type='table' and name='{groupKey}'"; SqliteCommand groupCommand = new SqliteCommand(queryGroupTableCmd, connection); var cmdReader = await (groupCommand.ExecuteReaderAsync()); bool exsitTable = (await cmdReader.ReadAsync()); if (exsitTable == false) { //create table string createTableCmd = $"create table {groupKey}(dataKey varchar({dataStrVarcharLen}) PRIMARY KEY,data varchar({dataStrVarcharLen}));"; SqliteCommand createTableCommand = new SqliteCommand(createTableCmd, connection); await createTableCommand.ExecuteNonQueryAsync(); } string updateDataCmd = $"INSERT OR REPLACE into {groupKey} (dataKey,data) values (@dataKey,@dataStr)"; SqliteCommand queryDataCommand = new SqliteCommand(updateDataCmd, connection); queryDataCommand.Parameters.AddWithValue("@dataKey",dataKey); queryDataCommand.Parameters.AddWithValue("@dataStr",dataStr); await queryDataCommand.ExecuteNonQueryAsync(); bool isExist = TryGetData(groupKey, dataKey, out string lastResult); if (isExist == false) { if (dataMap.ContainsKey(groupKey) == false) { dataMap.Add(groupKey, new Dictionary()); } } dataMap[groupKey][dataKey] = dataStr; bool hasExistedBefore = string.IsNullOrEmpty(lastResult) == false; if (hasExistedBefore == false) { TryRecordKey(groupKey); } complete?.Invoke(); } public async Task DataPersistentAsync(Action complete, params DataObject[] dataObjects) { IList writeTasks = new List(); foreach (var dataObject in dataObjects) { var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(dataObject.Key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; writeTasks.Add( DataPersistentAsync(groupKey, dataKey, dataObject.GetSerializeData(),null)); } await Task.WhenAll(writeTasks); complete?.Invoke(); } public string Read(string groupKey, string dataKey) { if (File.Exists(FilePath) == false) { return ""; } if (connection == null) { InitDBConnection(); } bool isExist = TryGetData(groupKey, dataKey, out string result); if (isExist) { return result; } string queryGroupTableCmd = $"select name from sqlite_master where type='table' and name='{groupKey}'"; SqliteCommand groupCommand = new SqliteCommand(queryGroupTableCmd, connection); var cmdReader = groupCommand.ExecuteReader(); bool exsitTable = cmdReader.Read(); if (exsitTable == false) { return ""; } string queryDataCmd = $"select data from {groupKey} where dataKey = '{dataKey}'"; SqliteCommand queryDataCommand = new SqliteCommand(queryDataCmd, connection); var queryDataReader = queryDataCommand.ExecuteReader(CommandBehavior.SingleResult); if (queryDataReader.Read()) { return queryDataReader.GetString("data"); } return ""; } public bool TryGetData(string groupKey, string dataKey, out string dataStr) { if (dataMap.ContainsKey(groupKey) == false) { dataStr = ""; return false; } return dataMap[groupKey].TryGetValue(dataKey, out dataStr); } public async Task DeleteAll() { TryRemoveAllGroupKey(); if (Directory.Exists(Path) == false) { return; } if (connection != null) { try { var disposeAsync = connection.DisposeAsync(); await disposeAsync; SqliteConnection.ClearPool(connection); connection = null; } catch (Exception e) { throw e; } } if (Directory.Exists(Path)) { bool isUse = await IOHelper.FileIsInUse(FilePath, 1000, 200); if (isUse) { Logger.LOG_ERROR($"File - {FilePath} has been occupied for a long time and cannot be deleted"); return; } Directory.Delete(Path, true); } this.Dispose(); } public void Delete(string groupKey, string dataKey) { if (File.Exists(FilePath) == false) { return; } if (connection == null) { InitDBConnection(); } string delDataCmd = $"delete from {groupKey} where dataKey='{dataKey}'"; SqliteCommand delDataCommand = new SqliteCommand(delDataCmd, connection); delDataCommand.ExecuteNonQuery(); if (dataMap != null) { if (dataMap.TryGetValue(groupKey, out var value)) { value.Remove(dataKey); } } } public void DeleteGroup(string groupKey) { if (File.Exists(FilePath) == false) { return; } if (connection == null) { InitDBConnection(); } string delDataCmd = $"delete from {groupKey}"; SqliteCommand delDataCommand = new SqliteCommand(delDataCmd, connection); delDataCommand.ExecuteNonQuery(); if (dataMap.ContainsKey(groupKey)) { dataMap.Remove(groupKey); } } public void TryRecordKey(string groupKey) { if (AllGroupKeys != null) { AllGroupKeys.Add(groupKey); } ArchiveOperationHelper.RecordKey(_archiveID, groupKey); } public void TryRemoveAllGroupKey() { ArchiveOperationHelper.DeleteAllGroupKeyFromDisk(); } private async Task> LoadAllGroupKeyFromDisk() { return await ArchiveOperationHelper.GetAllGroupKey(); } #pragma warning disable CS1998 public async Task GetSource() { if (AllGroupKeys == null) { AllGroupKeys = await LoadAllGroupKeyFromDisk(); } SqliteArchiveSourceWrapper wrapper = new SqliteArchiveSourceWrapper(); wrapper.sourcePath = FilePath; return wrapper; } #pragma warning restore CS1998 public async Task CloneTo(IDataArchiveSourceWrapper source) { var wrapper = source as SqliteArchiveSourceWrapper; if (string.IsNullOrEmpty(wrapper.sourcePath) || File.Exists(wrapper.sourcePath) == false) { return; } if (Directory.Exists(Path) == false) { Directory.CreateDirectory(Path); } byte[] buffer = new byte[0x1000]; int readLen; bool isUse = await IOHelper.FileIsInUse(wrapper.sourcePath, 1000 ,200); if (isUse) { Logger.LOG_ERROR($"File -{wrapper.sourcePath} has been occupied for a long time and cannot clone archive"); return; } using var reader = new FileStream(wrapper.sourcePath, FileMode.Open, FileAccess.Read, FileShare.None, bufferSize: 4096, useAsync: true); using var writer = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true); while ((readLen = await reader.ReadAsync(buffer, 0, buffer.Length)) != 0) { await writer.WriteAsync(buffer, 0, buffer.Length); } ArchiveOperationHelper.RecordAllGroupKeyWhenClone(_archiveID); } public async Task CloseIOAsync() { if (connection != null) { await connection.DisposeAsync(); } } public void Dispose() { if (connection != null) { connection.Dispose(); } archiveOperationHelper = null; connection = null; IsActive = false; GC.Collect(); GC.WaitForPendingFinalizers(); } public async Task DisposeAsync() { if (connection != null) { await connection.DisposeAsync(); } archiveOperationHelper = null; connection = null; IsActive = false; GC.Collect(); GC.WaitForPendingFinalizers(); } private string GetAndCombineDataFilePath() { string databasePath = DataArchiveConstData.GetAndCombineDataFilePath(Path, _archiveID.ToString()); return databasePath; } } } ================================================ FILE: System/DataArchiveOperation/SQLDataArchiveOperation.cs.meta ================================================ fileFormatVersion: 2 guid: bf92237a018fc9443bde177272bb8b5a MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: System/DataArchiveOperation.meta ================================================ fileFormatVersion: 2 guid: c1ab3a35ddb6480cb0cceabaaddd0ace timeCreated: 1722232746 ================================================ FILE: System/DataSystemInfoOperation/DataSystemInfoArchiveOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Threading.Tasks; using LitJson; namespace FlexiArchiveSystem.ArchiveOperation { public class DataSystemInfoArchiveOperation : FileModeDataArchiveOperation, IDataTypeSystemInfoOperation { public string SystemInfoPath { get => Path; set => Path = value; } public void ToSaveDataTypeSystemInfo(string groupKey, string dataKey, DataTypeSystemInfo dataTypeSystemInfo) { string jsonStr = dataTypeSystemInfo.Serialize(); DataPersistent(groupKey, dataKey, jsonStr); } public async void ToAsyncSaveDataTypeSystemInfo(string groupKey, string dataKey, DataTypeSystemInfo dataTypeSystemInfo) { string jsonStr = dataTypeSystemInfo.Serialize(); await DataPersistentAsync(groupKey, dataKey, jsonStr, null); } public override async Task DataPersistentAsync(Action complete, params DataObject[] dataObjects) { if (dataObjects.Length == 0) { return; } HashSet hashSet = new HashSet(); foreach (var dataObject in dataObjects) { string key = dataObject.Key; var keyTuple = DataKeyHandler.GetAndProcessKeyCollection(key); string groupKey = keyTuple.Item1; string dataKey = keyTuple.Item2; DataPersistentReadyWork(groupKey, dataKey, dataObject._dataType.SystemInfo.Serialize()); hashSet.Add(groupKey); } IList writeTasks = new List(); foreach (var groupKey in hashSet) { string groupFilePath = GetAndCombineDataFilePath(groupKey); writeTasks.Add(WriteToDiskAsync(groupFilePath, groupDataMap[groupKey].ToJson())); } await Task.WhenAll(writeTasks); complete?.Invoke(); } public bool ReadSystemInfo(string groupKey, string dataKey, out DataTypeSystemInfo systemInfo) { string jsonStr = Read(groupKey, dataKey); if (string.IsNullOrEmpty(jsonStr)) { systemInfo = default(DataTypeSystemInfo); return false; } systemInfo = JsonMapper.ToObject(jsonStr); return true; } public Type GetTypeOfDataValue(string groupKey, string dataKey) { bool success = ReadSystemInfo(groupKey, dataKey,out DataTypeSystemInfo dataTypeSystemInfo); if (success == false) { return null; } return Type.GetType(dataTypeSystemInfo.systemType); } public override void TryRecordKey(string groupKey) { //no record } #pragma warning disable CS1998 public override async Task DeleteAll() { if (File.Exists(SystemInfoPath)) { File.Delete(SystemInfoPath); } this.Dispose(); } #pragma warning restore CS1998 public override void TryRemoveAllGroupKey() { //no handler } protected override void RecordAllGroupKeys() { } } } ================================================ FILE: System/DataSystemInfoOperation/DataSystemInfoArchiveOperation.cs.meta ================================================ fileFormatVersion: 2 guid: c786041198c84c209712334b612757a8 timeCreated: 1723097691 ================================================ FILE: System/DataSystemInfoOperation/IDataTypeSystemInfoOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; namespace FlexiArchiveSystem { public interface IDataTypeSystemInfoOperation { public string SystemInfoPath { get; set; } public void ToSaveDataTypeSystemInfo(string groupKey, string dataKey, DataTypeSystemInfo dataTypeSystemInfo); public bool ReadSystemInfo(string groupKey, string dataKey, out DataTypeSystemInfo systemInfo); public Type GetTypeOfDataValue(string groupKey, string dataKey); } } ================================================ FILE: System/DataSystemInfoOperation/IDataTypeSystemInfoOperation.cs.meta ================================================ fileFormatVersion: 2 guid: 93ee4a2e4c204b4db5a110f58200ffe6 timeCreated: 1723096484 ================================================ FILE: System/DataSystemInfoOperation.meta ================================================ fileFormatVersion: 2 guid: e418b7036d1d44bfaf379484965e80b3 timeCreated: 1723097762 ================================================ FILE: System/DataType/Base/AbstractDataTypeWrapper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Reflection; using FlexiArchiveSystem.Assist; using FlexiArchiveSystem.Serialization; namespace FlexiArchiveSystem.DataType.Base { public abstract partial class AbstractDataTypeWrapper : IDataType, IEquatable { [Serializable] public class DataResultWrapper { public TData value; } protected DataResultWrapper _dataWrapper = new DataResultWrapper(); public T data => _dataWrapper.value; private T _diskData; public T diskData => _diskData; public event Action OnDirtyHandler; private DataTypeSystemInfo _systemInfo; DataTypeSystemInfo IDataType.SystemInfo => _systemInfo; protected ArchiveOperationType _ArchiveOperationType; private MethodInfo _methodInfoOfWriteData; public AbstractDataTypeWrapper(string dataStr) { if (string.IsNullOrEmpty(dataStr) == false) { _dataWrapper.value = DeSerialize(dataStr); _diskData = data; } _systemInfo = new DataTypeSystemInfo(this.GetType().ToString()); // DataTypeBinder.Register(this.GetType(),typeof(T)); //暂时没用上 } public void InjectArchiveOperationType(ArchiveOperationType archiveOperationType) { _ArchiveOperationType = archiveOperationType; } public MethodInfo GetWriteDataMethodInfo() { if (_methodInfoOfWriteData == null) { _methodInfoOfWriteData = this.GetType().GetMethod(nameof(this.Write),BindingFlags.Public | BindingFlags.Instance); } return _methodInfoOfWriteData; } public void Refresh() { _diskData = data; } public virtual string Serialize() { return DataTypeSerializeOperation.Serialize(_ArchiveOperationType, _dataWrapper); } protected virtual T DeSerialize(string dataStr) { return DataTypeSerializeOperation.DeSerialize(_ArchiveOperationType, dataStr); } public void WriteByGenericObject(object genericValue) { if (genericValue is T concreteData) { Write(concreteData); return; } Logger.LOG_ERROR("The data type does not match"); } public void Write(T data) { if (Equals(data) == false) { _dataWrapper.value = data; OnDirtyHandler?.Invoke(); } } public abstract bool Equals(T another); public void Reset() { Write(default(T)); } public override string ToString() { return ToString(data); } protected virtual string ToString(T data) { return data.ToString(); } protected virtual string DiskDataToString() { return ToString(_diskData); } } } ================================================ FILE: System/DataType/Base/AbstractDataTypeWrapper.cs.meta ================================================ fileFormatVersion: 2 guid: 85803697d07c4bdba8a8923434ed06b2 timeCreated: 1722068285 ================================================ FILE: System/DataType/Base/ValueWrapper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem.DataType.Base { public abstract class ValueWrapper where TWrapper : ValueWrapper, new() { public abstract TValue WrapperToValue(); public abstract void ValueToTheWrapper(TValue value); /// /// 该操作会将Value包装进引用类型的对象中,会产生额外的GC开销。 /// 建议降低使用频率 /// /// /// public static implicit operator ValueWrapper(TValue value) { var wrapper = new TWrapper(); wrapper.ValueToTheWrapper(value); return wrapper; } public static implicit operator TValue(ValueWrapper wrapper) { return wrapper.WrapperToValue(); } } } ================================================ FILE: System/DataType/Base/ValueWrapper.cs.meta ================================================ fileFormatVersion: 2 guid: 0a03f881bcd94bc0af47ed8c7411c764 timeCreated: 1724398935 ================================================ FILE: System/DataType/Base.meta ================================================ fileFormatVersion: 2 guid: 0b2701d2c2f040dda49442292dcd3185 timeCreated: 1724398921 ================================================ FILE: System/DataType/DataBoolean.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem { public class DataBoolean : AbstractDataTypeWrapper { public DataBoolean(string dataStr) : base(dataStr) { } public override bool Equals(bool another) { return another.Equals(data); } } } ================================================ FILE: System/DataType/DataBoolean.cs.meta ================================================ fileFormatVersion: 2 guid: e0728f5763c94bcfa3674186e0ca3b28 timeCreated: 1724380363 ================================================ FILE: System/DataType/DataDouble.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem { public class DataDouble : AbstractDataTypeWrapper { public DataDouble(string dataStr) : base(dataStr) { } public override bool Equals(double another) { return another.Equals(data); } } } ================================================ FILE: System/DataType/DataDouble.cs.meta ================================================ fileFormatVersion: 2 guid: 90710cd360ac4c4cbc69a0d665090714 timeCreated: 1724380395 ================================================ FILE: System/DataType/DataFloat.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem { public class DataFloat : AbstractDataTypeWrapper { public DataFloat(string dataStr) : base(dataStr) { } public override bool Equals(float another) { return another.Equals(data); } } } ================================================ FILE: System/DataType/DataFloat.cs.meta ================================================ fileFormatVersion: 2 guid: 351f8d8426f04204b6c57f4d950657fe timeCreated: 1724380374 ================================================ FILE: System/DataType/DataInteger.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem { public class DataInteger : AbstractDataTypeWrapper { public DataInteger(string dataStr) : base(dataStr) { } public override bool Equals(int another) { return another.Equals(data); } } } ================================================ FILE: System/DataType/DataInteger.cs.meta ================================================ fileFormatVersion: 2 guid: 37d162f90de7462e84ec47d886708c2b timeCreated: 1722071233 ================================================ FILE: System/DataType/DataLong.cs ================================================ using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem { public class DataLong : AbstractDataTypeWrapper { public DataLong(string dataStr) : base(dataStr) { } public override bool Equals(long another) { return another.Equals(data); } } } ================================================ FILE: System/DataType/DataLong.cs.meta ================================================ fileFormatVersion: 2 guid: 5cca932811774fe49ae8020716d69d32 timeCreated: 1726214126 ================================================ FILE: System/DataType/DataString.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem { public class DataString : AbstractDataTypeWrapper { public DataString(string dataStr) : base(dataStr) { } public override bool Equals(string other) { return string.Equals(other, _dataWrapper.value); } } } ================================================ FILE: System/DataType/DataString.cs.meta ================================================ fileFormatVersion: 2 guid: 21ab12705ec54a479105ade401c4384b timeCreated: 1722065659 ================================================ FILE: System/DataType/DataType_Object.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using FlexiArchiveSystem.DataType.Base; using FlexiArchiveSystem.Serialization; namespace FlexiArchiveSystem { /// /// 注意:虽然我提供了序列化任意对象的方式,但是我不推荐你使用这个序列化方式, /// 因为该方式会序列与值无关的所有元信息,其开销是巨大的。 /// 因此我在这里警告你,最好不要在正式项目中使用它。 /// /// Note:Although I did provide a way to serialize object,but i don't recommend you use this serialization method /// because it serialize all meta information that is not related to the value, which is expensive. /// So I'm here to warn you that it's best not to use it in formal projects. /// [Obsolete("Note: I don't recommend you use this serialization because of the performance overhead")] public partial class DataType_Object: AbstractDataTypeWrapper { public DataType_Object(string dataStr) : base(dataStr) { } public override bool Equals(System.Object other) => other.Equals(_dataWrapper.value); public override string Serialize() { string str = DataTypeSerializeOperation.SerializeToBinary(_ArchiveOperationType, _dataWrapper.value); DataResultWrapper wrapper = new DataResultWrapper(); wrapper.value = str; return DataTypeSerializeOperation.Serialize(_ArchiveOperationType,wrapper); } protected override System.Object DeSerialize(string dataStr) { string str = DataTypeSerializeOperation.DeSerialize(_ArchiveOperationType, dataStr); return DataTypeSerializeOperation.DeSerializeByBinary(_ArchiveOperationType, str); } } public class DataStructList : AbstractDataTypeWrapper> where T : struct { public DataStructList(string dataStr) : base(dataStr) { } public override bool Equals(List another) { return another == data; } public bool ElementsIsEqual(List another) { bool isSameRef = (another == data); if (isSameRef) { return true; } if (another == null || data == null) { return false; } if (another.Count != data.Count) { return false; } for (int i = 0; i < another.Count; i++) { if (another[i].Equals(data[i]) == false) { return false; } } return true; } protected override string ToString(List data) { string str = null; if (data != null) { str ="["; if (data.Count > 0) { str += data[0]; for (int i = 1; i < data.Count; i++) { str +="," + data[i]; } } str += "]"; } return str; } } public class DataStructArray : AbstractDataTypeWrapper where T : struct { public DataStructArray(string dataStr) : base(dataStr) { } public override bool Equals(T[] another) { return another == data; } public bool ElementsIsEqual(T[]another) { bool isSameRef = (another == data); if (isSameRef) { return true; } if (another == null || data == null) { return false; } if (another.Length != data.Length) { return false; } for (int i = 0; i < another.Length; i++) { if (another[i].Equals(data[i]) == false) { return false; } } return true; } protected override string ToString(T[] data) { string str = null; if (data != null) { str ="["; if (data.Length > 0) { str += data[0]; for (int i = 1; i < data.Length; i++) { str +="," + data[i]; } } str += "]"; } return str; } } public class DataList : AbstractDataTypeWrapper> { public DataList(string dataStr) : base(dataStr) { } public override bool Equals(List another) { return another == data; } public bool ElementsIsEqual(List another) { bool isSameRef = (another == data); if (isSameRef) { return true; } if (another == null || data == null) { return false; } if (another.Count != data.Count) { return false; } for (int i = 0; i < another.Count; i++) { if (another[i].Equals(data[i]) == false) { return false; } } return true; } protected override string ToString(List data) { string str = null; if (data != null) { str ="["; if (data.Count > 0) { str += data[0].ToString(); for (int i = 1; i < data.Count; i++) { str +="," + data[i]; } } str += "]"; } return str; } } public class DataArray : AbstractDataTypeWrapper { public DataArray(string dataStr) : base(dataStr) { } public override bool Equals(T[] another) { return another == data; } public bool ElementsIsEqual(T[] another) { bool isSameRef = (another == data); if (isSameRef) { return true; } if (another == null || data == null) { return false; } if (another.Length != data.Length) { return false; } for (int i = 0; i < another.Length; i++) { if (another[i].Equals(data[i]) == false) { return false; } } return true; } protected override string ToString(T[] data) { string str = null; if (data != null) { str ="["; if (data.Length > 0) { str += data[0].ToString(); for (int i = 1; i < data.Length; i++) { str +="," + data[i]; } } str += "]"; } return str; } } internal class DataDictionary : AbstractDataTypeWrapper> { public DataDictionary(string dataStr) : base(dataStr) { } public override bool Equals(Dictionary another) { return another.Equals(data); } protected override string ToString(Dictionary data) { string str = null; if (data != null) { str ="{"; if (data.Count > 0) { var keyCollections = data.Keys; foreach (var key in keyCollections) { str += string.Format("'{0}' : {1}, ", key, data[key].ToString()); } str = str.Remove(str.Length - 2,2); } str += "}"; } return str; } } } ================================================ FILE: System/DataType/DataType_Object.cs.meta ================================================ fileFormatVersion: 2 guid: cd4493d3ccc1441b8fdb9528715d98a2 timeCreated: 1726197347 ================================================ FILE: System/DataType.meta ================================================ fileFormatVersion: 2 guid: 16beccd615ff44bbb87bba097c0000f6 timeCreated: 1722065177 ================================================ FILE: System/Entry/DataArchiveContainer.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using FlexiArchiveSystem.ArchiveOperation; using FlexiArchiveSystem.Assist; using FlexiArchiveSystem.Setting; namespace FlexiArchiveSystem.Entry { public class DataArchiveContainer { private Dictionary dataGroupMap = new Dictionary(); public List dirtyDataGroupList = new List(); private IArchiveSetting _dataArchiveSetting; internal DataArchiveContainer(IArchiveSetting dataArchiveSetting) { this._dataArchiveSetting = dataArchiveSetting; } public DataObject GetDataObject(string group_key, string data_key) { var dataGroup = GetDataGroup(group_key); return dataGroup.GetDataObject(data_key); } public DataGroup GetDataGroup(string group_key) { DataGroup dataGroupObject = GetCacheDataGroup(group_key); if (dataGroupObject == null) { dataGroupObject = CreateNewDataGroup(group_key); dataGroupMap.Add(group_key, dataGroupObject); } return dataGroupObject; } private DataGroup GetCacheDataGroup(string key) { dataGroupMap.TryGetValue(key, out DataGroup dataGroupObject); return dataGroupObject; } private DataGroup CreateNewDataGroup(string key) { DataGroup dataGroupObject = new DataGroup(key); dataGroupObject.OnDirtyHandler += DataGroupHappenDirty; dataGroupObject.InjectArchiveSetting(_dataArchiveSetting); return dataGroupObject; } private void DataGroupHappenDirty(string groupKey) { if (dirtyDataGroupList.Contains(groupKey) == false) { dirtyDataGroupList.Add(groupKey); } } public void SwitchArchive(int archiveID) { if (archiveID != _dataArchiveSetting.CurrentArchiveID) { _dataArchiveSetting.SwitchArchive(archiveID); ClearMemoryCache(); } } public void Save() { foreach (var dirtyDataGroup in dirtyDataGroupList) { DataGroup dataGroupObject = GetCacheDataGroup(dirtyDataGroup); dataGroupObject.Save(); } dirtyDataGroupList.Clear(); } public async void SaveAsync(Action allComplete) { //TODO : cancel token IList saveList = new List(); foreach (var dirtyDataGroup in dirtyDataGroupList) { DataGroup dataGroupObject = GetCacheDataGroup(dirtyDataGroup); saveList.Add(dataGroupObject.SaveAsync()); } await Task.WhenAll(saveList); allComplete?.Invoke(); dirtyDataGroupList.Clear(); } public void SaveGroup(string group_key) { int index = dirtyDataGroupList.IndexOf(group_key); if (index < 0) { return; } var groupObject = GetCacheDataGroup(group_key); if (groupObject != null) { groupObject.Save(); dirtyDataGroupList.RemoveAt(index); } } public void SaveGroup(params string[] group_keys) { foreach (var group_key in group_keys) { int index = dirtyDataGroupList.IndexOf(group_key); if (index < 0) { continue; } var groupObject = GetCacheDataGroup(group_key); if (groupObject != null) { groupObject.Save(); dirtyDataGroupList.RemoveAt(index); } } } public void Delete(string group_key, string data_key) { DataObject dataObject = GetDataObject(group_key, data_key); dataObject.Delete(); } public async void DeleteAll() { #if !UNITY_EDITOR if (_dataArchiveSetting.IsAllowSaveDataSystemInfoInPlayerDevice) { await _dataArchiveSetting.DataTypeSystemInfoOperation.DeleteAll(); } #else await _dataArchiveSetting.DataTypeSystemInfoOperation.DeleteAll(); #endif await _dataArchiveSetting.DataArchiveOperation.DeleteAll(); _dataArchiveSetting.RefreshArchiveOperation(); ClearMemoryCache(); } public async void InstantiateNewArchive(Action complete = null) { int nextArchiveID = _dataArchiveSetting.GetNextArchiveID(); //Clone var currentDataArchiveOperation = _dataArchiveSetting.DataArchiveOperation; if (currentDataArchiveOperation.IsValidation == false) { Logger.LOG_WARNING("The current archive is invalid and will not be cloned. please check why the archive is invalid.\n" + "Archive invalid condition: byte is 0 or does not exist (or has existed)"); // Logger.LOG_WARNING("当前存档无效,将不会进行存档克隆。如有疑问,请检查存档无效的原因。\n" + // "存档无效条件:字节为0||不存在(或许曾经存在过)"); return; } IDataArchiveOperation newDataArchiveOperation = null; if (currentDataArchiveOperation is ICloneDataArchive iCloneDataArchive) { var source = await iCloneDataArchive.GetSource(); var targetArchiveOperation = DataArchiveOperationFactory.CreateArchiveOperationObject( _dataArchiveSetting.ArchiveOperationMode, _dataArchiveSetting.ModuleName, nextArchiveID); targetArchiveOperation.Init(_dataArchiveSetting.ModuleName, nextArchiveID); ICloneDataArchive target = targetArchiveOperation as ICloneDataArchive; if (target != null) { targetArchiveOperation.SetDataArchiveOperationHelper(currentDataArchiveOperation .ArchiveOperationHelper); await currentDataArchiveOperation.DisposeAsync(); await target.CloneTo(source); newDataArchiveOperation = target as IDataArchiveOperation; await CreateNewSystemInfoCoupleWithArchive(nextArchiveID); } } else { throw new Exception("ERROR: The current archive mode does not support the coexistence of multiple archives"); } _dataArchiveSetting.DataArchiveOperation = newDataArchiveOperation; _dataArchiveSetting.SetArchiveID(nextArchiveID); if (_dataArchiveSetting.IsLog) Logger.LOG("clone archive successful"); complete?.Invoke(); } private async Task CreateNewSystemInfoCoupleWithArchive(int nextArchiveID) { #if !UNITY_EDITOR if (_dataArchiveSetting.IsAllowSaveDataSystemInfoInPlayerDevice == false) { Logger.LOG("不允许保存SystemInfo"); return; } #endif var currentSystemInfoOperation = _dataArchiveSetting.DataTypeSystemInfoOperation; var source = await currentSystemInfoOperation.GetSource(); var newSystemInfo = DataArchiveOperationFactory.CreateArchiveSystemInfoOperationObject( _dataArchiveSetting.ArchiveOperationMode, _dataArchiveSetting.ModuleName, nextArchiveID); newSystemInfo.Init(_dataArchiveSetting.ModuleName, nextArchiveID); newSystemInfo.SetDataArchiveOperationHelper(currentSystemInfoOperation.ArchiveOperationHelper); await currentSystemInfoOperation.DisposeAsync(); await newSystemInfo.CloneTo(source); _dataArchiveSetting.DataTypeSystemInfoOperation = newSystemInfo; } public void ClearMemoryCache() { if (dataGroupMap != null) { dataGroupMap.Clear(); } dirtyDataGroupList.Clear(); } } } ================================================ FILE: System/Entry/DataArchiveContainer.cs.meta ================================================ fileFormatVersion: 2 guid: 1629c652aac3586418856e907e7f7ab0 MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: System/Entry.meta ================================================ fileFormatVersion: 2 guid: b76b3e2d64ea4dab90c09ae8de3de45d timeCreated: 1724293125 ================================================ FILE: System/Extension/DiskAndMemoryData.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- namespace FlexiArchiveSystem { public struct DiskAndMemoryData { public T data; public T diskData; public DiskAndMemoryData(T data, T diskData) { this.data = data; this.diskData = diskData; } } } ================================================ FILE: System/Extension/DiskAndMemoryData.cs.meta ================================================ fileFormatVersion: 2 guid: 6ec8bf75d1b24e308993a5e7d53a595e timeCreated: 1728539787 ================================================ FILE: System/Extension/FlexiDataContainer.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.DataType.Base; namespace FlexiArchiveSystem.Extension { public interface IFlexiWriteOrReadArchiveOperation { public IFlexiDataArchiveManager DataArchiveManager { get; } public DiskAndMemoryData GetValue(string GroupKey, string SubKey) where TDataType : AbstractDataTypeWrapper; public TValue GetDiskValue(string GroupKey, string SubKey) where TDataType : AbstractDataTypeWrapper; public TValue GetMemoryValue(string GroupKey, string SubKey) where TDataType : AbstractDataTypeWrapper; public void ModifyValue(string GroupKey, string SubKey, TValue value) where TDataType : AbstractDataTypeWrapper; } public abstract class FlexiDataContainer : IFlexiWriteOrReadArchiveOperation { public virtual IFlexiDataArchiveManager DataArchiveManager{ get; protected set; } public void SetDataArchiveManager(IFlexiDataArchiveManager dataArchiveManager) { DataArchiveManager = dataArchiveManager; } public DiskAndMemoryData GetValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { return DataArchiveManager.GetValue(GroupKey, SubKey); } public TValue GetDiskValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { return DataArchiveManager.GetDiskValue(GroupKey, SubKey); } public TValue GetMemoryValue(string GroupKey, string SubKey) where TDataType: AbstractDataTypeWrapper { return DataArchiveManager.GetMemoryValue(GroupKey, SubKey); } public void ModifyValue(string GroupKey, string SubKey, TValue value) where TDataType: AbstractDataTypeWrapper { DataArchiveManager.ModifyValue(GroupKey, SubKey, value); } } } ================================================ FILE: System/Extension/FlexiDataContainer.cs.meta ================================================ fileFormatVersion: 2 guid: a3ff3cf0133143c1a0dd920ce9677f9b timeCreated: 1728734299 ================================================ FILE: System/Extension.meta ================================================ fileFormatVersion: 2 guid: c5b431db2ed047c8ace5ef3ce4061a78 timeCreated: 1728734284 ================================================ FILE: System/Helper/DataArchiveOperationHelper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using FlexiArchiveSystem.ArchiveOperation.IO; using FlexiArchiveSystem.Assist; using LitJson; namespace FlexiArchiveSystem.ArchiveOperation { public class DataArchiveOperationHelper { private string _ArchiveSystemName; private List GroupKeys; private JsonData groupKeysJsonData; private bool GroupKeysJsonDataIsDirty => groupKeysJsonData == null; private int _archiveID = -1; private Dictionary WriteCancellationTokenSourceMap = new Dictionary(); public void SetArchiveID(int archiveID) { _archiveID = archiveID; } public void Init(string ArchiveSystemName) { _ArchiveSystemName = ArchiveSystemName; } public void RecordKey(int archiveID, string groupKey) { UpdateDirtyState(archiveID); //record the key TryAddGroupKey(groupKey); } public void RecordAllGroupKey(int archiveID, List groupKeys) { UpdateDirtyState(archiveID); //record the key GroupKeys = groupKeys; groupKeysJsonData = ConvertToJsonData(groupKeys); WriteToDisk(groupKeysJsonData); } /// /// Ensure that the helper is the same and the data is changed /// /// public async void RecordAllGroupKeyWhenClone(int archiveID) { if (GroupKeysJsonDataIsDirty) { //cache await GetAllGroupKey(); } SetArchiveID(archiveID); WriteToDisk(groupKeysJsonData); } public void UpdateDirtyState(int archiveID) { if (archiveID != _archiveID) { SetArchiveID(archiveID); groupKeysJsonData = null; //GroupKeysJsonDataIsDirty is true } } private async void TryAddGroupKey(string groupKey) { var groupKeys = await GetAllGroupKey(); if (groupKeys == null) { groupKeys = new List(); } foreach (var key in groupKeys) { if (key == groupKey) { return; } } groupKeys.Add(groupKey); GroupKeys = groupKeys; groupKeysJsonData.Add(groupKey); await WriteAysncToDisk(groupKeysJsonData); } public async Task> GetAllGroupKey() { if (GroupKeysJsonDataIsDirty == false) { return GroupKeys; } groupKeysJsonData = await TryGetLoadGroupKeysJsonData(); if (groupKeysJsonData == null) { return null; } GroupKeys = JsonMapper.ToObject>(groupKeysJsonData.ToJson()); return GroupKeys; } private JsonData ConvertToJsonData(List groupKeys) { JsonData jsonData = new JsonData(); foreach (var groupKey in groupKeys) { jsonData.Add(groupKey); } return jsonData; } private void WriteToDisk(JsonData jsonData) { using (StreamWriter streamWriter = new StreamWriter(DataArchiveConstData.GetArchiveGroupKeysFilePath(_ArchiveSystemName, _archiveID))) { streamWriter.AutoFlush = false; streamWriter.Write(jsonData.ToJson()); streamWriter.Flush(); } } private async Task WriteAysncToDisk(JsonData jsonData) { WriteCancellationTokenSourceMap.TryGetValue(_archiveID,out var tokenSource); if (tokenSource != null) { tokenSource.Cancel(); tokenSource.Dispose(); } string filePath = DataArchiveConstData.GetArchiveGroupKeysFilePath(_ArchiveSystemName, _archiveID); bool isUse = await IOHelper.FileIsInUse(filePath, 300,100); if (isUse) { Logger.LOG_ERROR($"File - {filePath} has been occupied for a long time and cannot write auxiliary information"); // Logger.LOG_ERROR($"文件{filePath}长时间被占用,无法写入辅助信息"); return; } using (StreamWriter streamWriter = new StreamWriter(filePath)) { tokenSource = new CancellationTokenSource(); WriteCancellationTokenSourceMap[_archiveID] = tokenSource; ReadOnlyMemory readOnlyMemory = new ReadOnlyMemory(jsonData.ToJson().ToCharArray()); streamWriter.AutoFlush = false; await streamWriter.WriteAsync(readOnlyMemory, tokenSource.Token); await streamWriter.FlushAsync(); tokenSource.Dispose(); WriteCancellationTokenSourceMap.Remove(_archiveID); } } private async Task TryGetLoadGroupKeysJsonData() { if (GroupKeysJsonDataIsDirty == false) { return groupKeysJsonData; } string saveGroupPath = DataArchiveConstData.GetArchiveGroupKeysFilePath(_ArchiveSystemName, _archiveID); groupKeysJsonData = JsonMapper.ToObject(await LoadGroupKeysFromDisk(saveGroupPath)); return groupKeysJsonData; } private async Task LoadGroupKeysFromDisk(string path) { if (File.Exists(path) == false) { return ""; } var sb = new StringBuilder(); using (var sourceStream = new StreamReader(path)) { char[] buffer = new char[50]; int readLen; while ((readLen = await sourceStream.ReadAsync(buffer, 0,buffer.Length)) != 0) { sb.Append(buffer, 0, readLen); } } return sb.ToString(); } public void DeleteAllGroupKeyFromDisk() { string path = DataArchiveConstData.GetArchiveGroupKeysFilePath(_ArchiveSystemName, _archiveID); if (File.Exists(path)) { File.Delete(path); } GroupKeys = null; groupKeysJsonData = null; } public async void RemoveGroupKey(string groupKey) { var groupKeys = await GetAllGroupKey(); groupKeys.Remove(groupKey); groupKeysJsonData = ConvertToJsonData(groupKeys); WriteToDisk(groupKeysJsonData); GroupKeys = groupKeys; } } } ================================================ FILE: System/Helper/DataArchiveOperationHelper.cs.meta ================================================ fileFormatVersion: 2 guid: 30507f179aae418a94e14c239e69b500 timeCreated: 1723269468 ================================================ FILE: System/Helper.meta ================================================ fileFormatVersion: 2 guid: bc777f478458416c9fbbf0cf07ca0e40 timeCreated: 1723269477 ================================================ FILE: System/Manager/IFlexiDataArchiveManager.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; namespace FlexiArchiveSystem { /// /// Please go to Unity-IFlexiDataArchiveManager what is core code; /// public abstract partial class IFlexiDataArchiveManager { protected abstract ArchiveSettingWrapper LoadDataArchiveSettingFromDisk(); } } ================================================ FILE: System/Manager/IFlexiDataArchiveManager.cs.meta ================================================ fileFormatVersion: 2 guid: c1cbc14af3d749d4999bab518c879107 timeCreated: 1724327514 ================================================ FILE: System/Manager.meta ================================================ fileFormatVersion: 2 guid: 5097d1dc931f48c49fd8d1848eaeec72 timeCreated: 1724292947 ================================================ FILE: System/SerializeOperation/DataTypeSerializeOperation.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using FlexiArchiveSystem.DataType.Base; using LitJson; namespace FlexiArchiveSystem.Serialization { public class DataTypeSerializeOperation { public static string Serialize(ArchiveOperationType archiveOperationType, T data) { return JsonMapper.ToJson(data); } public static T DeSerialize(ArchiveOperationType archiveOperationType, string dataStr) { return JsonMapper.ToObject.DataResultWrapper>(dataStr).value; } public static string SerializeToBinary(ArchiveOperationType archiveOperationType, T data) { string str; using (MemoryStream stream = new MemoryStream()) { var binaryFormatter = new BinaryFormatter(); binaryFormatter.Serialize(stream , data); byte[] bytes = stream.GetBuffer();; str = Convert.ToBase64String(bytes); } return str; } public static T DeSerializeByBinary(ArchiveOperationType archiveOperationType, string dataStr) { T result; using (MemoryStream stream = new MemoryStream(Convert.FromBase64String(dataStr))) { var binaryFormatter = new BinaryFormatter(); stream.Position = 0; object obj = binaryFormatter.Deserialize(stream); result = (T)obj; } return result; } } } ================================================ FILE: System/SerializeOperation/DataTypeSerializeOperation.cs.meta ================================================ fileFormatVersion: 2 guid: 3cc0e1cea63a445aaa2e7d716c4c7e16 timeCreated: 1723809343 ================================================ FILE: System/SerializeOperation/JsonReaderWithCached.cs ================================================ namespace FlexiArchiveSystem.Serialization { public class JsonReaderWithCached { } } ================================================ FILE: System/SerializeOperation/JsonReaderWithCached.cs.meta ================================================ fileFormatVersion: 2 guid: 6a39f3944ee84bbf89f711a3509a896d timeCreated: 1723271089 ================================================ FILE: System/SerializeOperation.meta ================================================ fileFormatVersion: 2 guid: e7ff6c42af82466db9b66407a3a8afd4 timeCreated: 1723809326 ================================================ FILE: System/Setting/ArchiveSettingWrapper.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using FlexiArchiveSystem.Setting; namespace FlexiArchiveSystem { public struct ArchiveSettingWrapper { public readonly IArchiveSetting ArchiveSetting; public ArchiveSettingWrapper(IArchiveSetting setting) { ArchiveSetting = setting; } } } ================================================ FILE: System/Setting/ArchiveSettingWrapper.cs.meta ================================================ fileFormatVersion: 2 guid: 2343fde98b66458482d0b736413e7025 timeCreated: 1724759234 ================================================ FILE: System/Setting/FlexiArchiveSetting.cs ================================================ //------------------------------------------------- // Flexi Archive System // Copyright (c) 2024 温文. All rights reserved. // blog: https://www.playcreator.cn // email: yixiangluntan@163.com //------------------------------------------------- using System.Collections.Generic; using FlexiArchiveSystem.ArchiveOperation; namespace FlexiArchiveSystem.Setting { /// /// Please go to Unity-FlexiArchiveSetting what is core code; /// public partial class FlexiArchiveSetting { } public interface IArchiveSetting { public ArchiveOperationType ArchiveOperationMode { get; } public bool IsLog { get; } public abstract string ModuleName { get; } public bool IsAllowSaveDataSystemInfoInPlayerDevice { get; } public int CurrentArchiveID { get; } public List AllArchiveID { get; } public IDataArchiveOperation DataArchiveOperation { get; set; } public DataSystemInfoArchiveOperation DataTypeSystemInfoOperation { get; set; } public void Init(); public int GetNextArchiveID(); public void SetArchiveID(int val, bool isUpdateToDisk = true); public void RefreshArchiveOperation(); public void SwitchArchive(int archiveID); public void CreateOrRebuildArchiveOperation(); public List GetAllArchiveID(); public void ClearAllArchiveIDCacheInMemory(); } } ================================================ FILE: System/Setting/FlexiArchiveSetting.cs.meta ================================================ fileFormatVersion: 2 guid: 5e9c44cf00e94936b33fcacf7af5bbe1 timeCreated: 1722245998 ================================================ FILE: System/Setting.meta ================================================ fileFormatVersion: 2 guid: d7fed3b555ef47199f71edfa3f9e4fc7 timeCreated: 1723606503 ================================================ FILE: System.meta ================================================ fileFormatVersion: 2 guid: b6c15d7284fd20b47b51c4150161f1fe folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Third-Party Notices.txt ================================================ This asset is governed by the Asset Store EULA; however, the following components are governed by the licenses indicated below: (A.) System.Data -------------- The MIT License (MIT) Copyright (c) .NET Foundation and Contributors All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. (B.) sqlite3 ----------------- Public Domain All of the code and documentation in SQLite has been dedicated to the public domain by the authors. All code authors, and representatives of the companies they work for, have signed affidavits dedicating their contributions to the public domain and originals of those signed affidavits are stored in a firesafe at the main offices of Hwaci. All contributors are citizens of countries that allow creative works to be dedicated into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute the original SQLite code, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. The previous paragraph applies to the deliverable code and documentation in SQLite - those parts of the SQLite library that you actually bundle and ship with a larger application. Some scripts used as part of the build process (for example the "configure" scripts generated by autoconf) might fall under other open-source licenses. Nothing from these build scripts ever reaches the final deliverable SQLite library, however, and so the licenses associated with those scripts should not be a factor in assessing your rights to copy and use the SQLite library. All of the deliverable code in SQLite has been written from scratch. No code has been taken from other projects or from the open internet. Every line of code can be traced back to its original author, and all of those authors have public domain dedications on file. So the SQLite code base is clean and is uncontaminated with licensed code from other projects. (C.) LitJson ------------ Public Domain This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to Thank you for reading this notice. Following the tradition of other public domain projects, here's a blessing: May you find forgiveness for yourself and forgive others. May you experience and share the gift of unconditional love. May you see light, wherever the illusion of darkness appears. (D.) Mono.Data.Sqlite ------------ Public Domain Copyright 2001-2019 Mono Project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.