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