[
  {
    "path": ".github/workflows/notify-discord-on-release.yml",
    "content": "name: Notify Discord on Release or Tag\n\non:\n  release:\n    types: [published]\n  push:\n    tags:\n      - '*'\n\njobs:\n  notify-discord:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Send release/tag info to Discord\n        env:\n          DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}\n          EVENT_NAME: ${{ github.event_name }}\n          RELEASE_TITLE: ${{ github.event.release.name }}\n          RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}\n          RELEASE_NOTE: ${{ github.event.release.body }}\n          RELEASE_AUTHOR: ${{ github.event.release.author.login }}\n          PUSH_TAG_NAME: ${{ github.ref_name }}\n          REPO: ${{ github.repository }}\n          ACTOR: ${{ github.actor }}\n        run: |\n          if [ \"$EVENT_NAME\" = \"release\" ]; then\n            TITLE=\"${RELEASE_TITLE:-No release title}\"\n            TAG=\"${RELEASE_TAG_NAME:-Unknown tag}\"\n            NOTE=\"${RELEASE_NOTE}\"\n            AUTHOR=\"${RELEASE_AUTHOR:-$ACTOR}\"\n            EVENT_LABEL=\"GitHub Release\"\n          else\n            TITLE=\"Tag created\"\n            TAG=\"${PUSH_TAG_NAME:-Unknown tag}\"\n            NOTE=\"A new tag was pushed without creating a GitHub Release.\"\n            AUTHOR=\"$ACTOR\"\n            EVENT_LABEL=\"Git Tag\"\n          fi\n\n          if [ -z \"$NOTE\" ]; then\n            NOTE=\"(empty)\"\n          fi\n\n          if [ ${#NOTE} -gt 1000 ]; then\n            NOTE=\"${NOTE:0:1000}...\"\n          fi\n\n          jq -n \\\n            --arg event \"$EVENT_LABEL\" \\\n            --arg title \"$TITLE\" \\\n            --arg tag \"$TAG\" \\\n            --arg note \"$NOTE\" \\\n            --arg repo \"$REPO\" \\\n            --arg actor \"$ACTOR\" \\\n            --arg author \"$AUTHOR\" \\\n            '{\n              embeds: [\n                {\n                  title: $event,\n                  fields: [\n                    { \"name\": \"Repository\", \"value\": $repo, \"inline\": false },\n                    { \"name\": \"Triggered By\", \"value\": $actor, \"inline\": false },\n                    { \"name\": \"Author\", \"value\": $author, \"inline\": false },\n                    { \"name\": \"Title\", \"value\": $title, \"inline\": false },\n                    { \"name\": \"Tag Name\", \"value\": $tag, \"inline\": false },\n                    { \"name\": \"Note\", \"value\": $note, \"inline\": false }\n                  ]\n                }\n              ]\n            }' > payload.json\n\n          cat payload.json\n\n          curl --fail-with-body \\\n               -H \"Content-Type: application/json\" \\\n               -X POST \\\n               -d @payload.json \\\n               \"$DISCORD_WEBHOOK_URL\"\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 VirtueSky\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"
  },
  {
    "path": "LICENSE.meta",
    "content": "fileFormatVersion: 2\nguid: 602f2b07fec879a41853f704b2b884a5\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "README.md",
    "content": "# Core scriptable object architecture for building Unity games (Android & iOS)\n\n<p align=\"left\">\n  <a>\n    <img alt=\"Made With Unity\" src=\"https://img.shields.io/badge/made%20with-Unity-57b9d3.svg?logo=Unity\">\n  </a>\n  <a>\n    <img alt=\"License\" src=\"https://img.shields.io/github/license/VirtueSky/sunflower?logo=github\">\n  </a>\n  <a>\n    <img alt=\"Last Commit\" src=\"https://img.shields.io/github/last-commit/VirtueSky/sunflower?logo=Mapbox&color=orange\">\n  </a>\n  <a>\n    <img alt=\"Repo Size\" src=\"https://img.shields.io/github/repo-size/VirtueSky/sunflower?logo=VirtualBox\">\n  </a>\n  <a>\n    <img alt=\"Last Release\" src=\"https://img.shields.io/github/v/release/VirtueSky/sunflower?include_prereleases&logo=Dropbox&color=yellow\">\n  </a>\n</p>\n\n### Unity 2022.3 LTS\n## How To Install\n### 1: Download the repository and drop it into folder `Assets`\n### 2: Add the line below to `Packages/manifest.json`\n\n- for version `3.5.4`\n```json\n{\n  \"scopedRegistries\": [\n    {\n      \"name\": \"npm\",\n      \"url\": \"https://registry.npmjs.org/\",\n      \"scopes\": [\n        \"com.kyrylokuzyk\"\n      ]\n    }\n  ],\n  \"dependencies\": {\n    \"com.virtuesky.sunflower\":\"https://github.com/VirtueSky/sunflower.git#3.5.4\"\n  }\n}\n\n```\n- depencies:\n```json\n\"com.unity.nuget.newtonsoft-json\": \"3.2.1\",\n\"com.unity.serialization\": \"3.1.1\",\n\"com.unity.collections\": \"2.1.4\",\n\"com.unity.textmeshpro\": \"3.0.8\",\n\"com.cysharp.unitask\": \"https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10\",\n\"com.kyrylokuzyk.primetween\": \"1.3.8\",\n```\n## Includes modules\n\n```bash\n├── Core (Update only called once in Monobehaviour, Delay...)\n├── Advertising (Support for Max, Admob and IronSource)\n├── In App Purchase (IAP)\n├── Asset Finder\n├── Audio\n├── Button\n├── Data\n├── Scriptable Event\n├── Scriptable Variable\n├── Firebase Remote Config\n├── Tracking (Firebase Analytics, Adjust, AppsFlyer)\n├── Tri-Inspector\n├── Level Editor\n├── Mobile Notification\n├── Object Pooling\n├── Localization\n├── FolderIcons\n├── Hierarchy\n├── In app review\n├── SimpleJSON\n├── Tracking Revenue (by Firebase analytic, Adjust or Appsflyer)\n├── Vibration (Vibration native support for android & ios)\n├── Game Service (Sign in with apple id / google play games service)\n├── Misc (Extension support Transform, SafeArea, Play Animancer, Skeleton,...)\n├── Touch Input\n├── Component\n```\n\n#### Note:\n\n- [See Document](https://github.com/VirtueSky/sunflower/wiki)\n- [Project implementation](https://github.com/VirtueSky/TheBeginning)\n- [Core has similar modules but does not use scriptable architecture](https://github.com/wolf-package/unity-common)\n\n[Join Discord to receive update notifications](https://discord.gg/bpcUyHRZ)\n"
  },
  {
    "path": "README.md.meta",
    "content": "fileFormatVersion: 2\nguid: 7b4ab53c22cea684aa8898738b406520\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Editor/AdSettingEditor.cs",
    "content": "﻿#if UNITY_EDITOR\nusing System;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.Ads\n{\n    [CustomEditor(typeof(AdSetting), true)]\n    public class AdSettingEditor : Editor\n    {\n        private AdSetting _adSetting;\n\n        private SerializedProperty _useApplovin;\n        private SerializedProperty _useAdmob;\n        private SerializedProperty _useLevelPlay;\n        private SerializedProperty _enableTrackAdRevenue;\n        private SerializedProperty _adCheckingInterval;\n        private SerializedProperty _adLoadingInterval;\n\n        private SerializedProperty _sdkKey;\n\n        private SerializedProperty _maxBannerVariable;\n        private SerializedProperty _maxInterVariable;\n        private SerializedProperty _maxRewardVariable;\n        private SerializedProperty _maxAppOpenVariable;\n\n\n        private SerializedProperty _admobBannerVariable;\n        private SerializedProperty _admobInterVariable;\n        private SerializedProperty _admobRewardVariable;\n        private SerializedProperty _admobRewardInterVariable;\n        private SerializedProperty _admobAppOpenVariable;\n        private SerializedProperty _admobNativeOverlayVariable;\n        private SerializedProperty _autoTrackingAdImpressionAdmob;\n        private SerializedProperty _admobEnableTestMode;\n        private SerializedProperty _enableGDPR;\n        private SerializedProperty _enableGDPRTestMode;\n        private SerializedProperty _admobDevicesTest;\n\n        private SerializedProperty _androidAppKey;\n        private SerializedProperty _iOSAppKey;\n        private SerializedProperty _useTestAppKey;\n        private SerializedProperty _levelPlayBannerVariable;\n        private SerializedProperty _levelPlayInterVariable;\n        private SerializedProperty _levelPlayRewardVariable;\n\n        const string pathMax = \"/Ads/Applovin\";\n        const string pathAdmob = \"/Ads/Admob\";\n        const string pathIronSource = \"/Ads/LevelPlay\";\n\n        void Initialize()\n        {\n            _adSetting = target as AdSetting;\n            _useApplovin = serializedObject.FindProperty(\"useAppLovin\");\n            _useAdmob = serializedObject.FindProperty(\"useAdmob\");\n            _useLevelPlay = serializedObject.FindProperty(\"useLevelPlay\");\n            _enableTrackAdRevenue = serializedObject.FindProperty(\"enableTrackAdRevenue\");\n            _adCheckingInterval = serializedObject.FindProperty(\"adCheckingInterval\");\n            _adLoadingInterval = serializedObject.FindProperty(\"adLoadingInterval\");\n\n            _sdkKey = serializedObject.FindProperty(\"sdkKey\");\n            _maxBannerVariable = serializedObject.FindProperty(\"maxBannerVariable\");\n            _maxInterVariable = serializedObject.FindProperty(\"maxInterVariable\");\n            _maxRewardVariable = serializedObject.FindProperty(\"maxRewardVariable\");\n            _maxAppOpenVariable = serializedObject.FindProperty(\"maxAppOpenVariable\");\n\n            _admobBannerVariable = serializedObject.FindProperty(\"admobBannerVariable\");\n            _admobInterVariable = serializedObject.FindProperty(\"admobInterVariable\");\n            _admobRewardVariable = serializedObject.FindProperty(\"admobRewardVariable\");\n            _admobRewardInterVariable = serializedObject.FindProperty(\"admobRewardInterVariable\");\n            _admobAppOpenVariable = serializedObject.FindProperty(\"admobAppOpenVariable\");\n            _admobNativeOverlayVariable = serializedObject.FindProperty(\"admobNativeOverlayVariable\");\n            _autoTrackingAdImpressionAdmob = serializedObject.FindProperty(\"autoTrackingAdImpressionAdmob\");\n            _admobEnableTestMode = serializedObject.FindProperty(\"admobEnableTestMode\");\n            _admobDevicesTest = serializedObject.FindProperty(\"admobDevicesTest\");\n            _enableGDPR = serializedObject.FindProperty(\"enableGDPR\");\n            _enableGDPRTestMode = serializedObject.FindProperty(\"enableGDPRTestMode\");\n\n            _androidAppKey = serializedObject.FindProperty(\"androidAppKey\");\n            _iOSAppKey = serializedObject.FindProperty(\"iOSAppKey\");\n            _useTestAppKey = serializedObject.FindProperty(\"useTestAppKey\");\n            _levelPlayBannerVariable = serializedObject.FindProperty(\"levelPlayBannerVariable\");\n            _levelPlayInterVariable = serializedObject.FindProperty(\"levelPlayInterVariable\");\n            _levelPlayRewardVariable = serializedObject.FindProperty(\"levelPlayRewardVariable\");\n        }\n\n        void Draw()\n        {\n            serializedObject.Update();\n            Initialize();\n            // EditorGUILayout.LabelField(\"ADS SETTING\", EditorStyles.boldLabel);\n            //GuiLine(2);\n            GUILayout.Space(10);\n            EditorGUILayout.PropertyField(_adCheckingInterval);\n            EditorGUILayout.PropertyField(_adLoadingInterval);\n            EditorGUILayout.PropertyField(_useApplovin);\n            EditorGUILayout.PropertyField(_useAdmob);\n            EditorGUILayout.PropertyField(_useLevelPlay);\n            EditorGUILayout.PropertyField(_enableTrackAdRevenue);\n            EditorGUILayout.PropertyField(_enableGDPR);\n            if (_enableGDPR.boolValue)\n            {\n                EditorGUILayout.PropertyField(_enableGDPRTestMode);\n            }\n\n            GUILayout.Space(10);\n            if (_useApplovin.boolValue) SetupMax();\n            if (_useAdmob.boolValue) SetupAdmob();\n            if (_useLevelPlay.boolValue) SetupIronSource();\n\n            EditorUtility.SetDirty(target);\n            serializedObject.ApplyModifiedProperties();\n        }\n\n\n        public override void OnInspectorGUI()\n        {\n            Draw();\n        }\n\n        void SetupMax()\n        {\n            EditorGUILayout.LabelField(\"Applovin - Max\", StyleLabel());\n            GuiLine(1);\n            GUILayout.Space(10);\n            EditorGUILayout.PropertyField(_sdkKey);\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_maxBannerVariable);\n            if (_maxBannerVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _maxBannerVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<MaxBannerVariable>(pathMax);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_maxInterVariable);\n            if (_maxInterVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _maxInterVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<MaxInterVariable>(pathMax);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_maxRewardVariable);\n            if (_maxRewardVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _maxRewardVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<MaxRewardVariable>(pathMax);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_maxAppOpenVariable);\n            if (_maxAppOpenVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _maxAppOpenVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<MaxAppOpenVariable>(pathMax);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            GUILayout.Space(10);\n        }\n\n        void SetupAdmob()\n        {\n            EditorGUILayout.LabelField(\"Google - Admob\", StyleLabel());\n            GuiLine(1);\n            GUILayout.Space(10);\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_admobBannerVariable);\n            if (_admobBannerVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _admobBannerVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<AdmobBannerVariable>(pathAdmob);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_admobInterVariable);\n            if (_admobInterVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _admobInterVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<AdmobInterVariable>(pathAdmob);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_admobRewardVariable);\n            if (_admobRewardVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _admobRewardVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<AdmobRewardVariable>(pathAdmob);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_admobRewardInterVariable);\n            if (_admobRewardInterVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _admobRewardInterVariable.objectReferenceValue =\n                        CreateAsset\n                            .CreateAndGetScriptableAsset<AdmobRewardInterVariable>(pathAdmob);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_admobAppOpenVariable);\n            if (_admobAppOpenVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _admobAppOpenVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<AdmobAppOpenVariable>(pathAdmob);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_admobNativeOverlayVariable);\n            if (_admobNativeOverlayVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _admobNativeOverlayVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<AdmobNativeOverlayVariable>(pathAdmob);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.PropertyField(_autoTrackingAdImpressionAdmob);\n            EditorGUILayout.PropertyField(_admobEnableTestMode);\n            EditorGUILayout.PropertyField(_admobDevicesTest);\n            GUI.enabled = false;\n            EditorGUILayout.TextField(\"App Id Test\", \"ca-app-pub-3940256099942544~3347511713\");\n            GUI.enabled = true;\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Open GoogleAdmobSetting\", GUILayout.Height(20)))\n            {\n                EditorApplication.ExecuteMenuItem(\"Assets/Google Mobile Ads/Settings...\");\n            }\n\n            GUILayout.Space(10);\n        }\n\n        void SetupIronSource()\n        {\n            EditorGUILayout.LabelField(\"Unity - LevelPlay\", StyleLabel());\n            GuiLine(1);\n            GUILayout.Space(10);\n            EditorGUILayout.PropertyField(_androidAppKey);\n            EditorGUILayout.PropertyField(_iOSAppKey);\n            EditorGUILayout.PropertyField(_useTestAppKey);\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_levelPlayBannerVariable);\n            if (_levelPlayBannerVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _levelPlayBannerVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<LevelPlayBannerVariable>(pathIronSource);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_levelPlayInterVariable);\n            if (_levelPlayInterVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _levelPlayInterVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<LevelPlayInterVariable>(pathIronSource);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(_levelPlayRewardVariable);\n            if (_levelPlayRewardVariable.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    _levelPlayRewardVariable.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<LevelPlayRewardVariable>(pathIronSource);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n            GUILayout.Space(10);\n        }\n\n        GUIStyle StyleLabel()\n        {\n            var style = new GUIStyle();\n            style.fontSize = 14;\n            style.normal.textColor = Color.white;\n            return style;\n        }\n\n        void GuiLine(int i_height = 1)\n        {\n            Rect rect = EditorGUILayout.GetControlRect(false, i_height);\n\n            rect.height = i_height;\n\n            EditorGUI.DrawRect(rect, new Color32(0, 0, 0, 255));\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Advertising/Editor/AdSettingEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6439b65cc7b34375ace31c6d3f331f3e\ntimeCreated: 1700021422"
  },
  {
    "path": "VirtueSky/Advertising/Editor/AdsWindowEditor.cs",
    "content": "#if UNITY_EDITOR\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.Ads\n{\n    public class AdsWindowEditor : EditorWindow\n    {\n        //     private Vector2 _scrollPosition;\n        //     private Editor _editor;\n        //\n        //     private AdSetting _adSetting;\n        //\n        //     private bool isSetupTheme = false;\n        //\n        //     [MenuItem(\"Sunflower/Ads/AdSetting &4\", false)]\n        //     public static void OpenAdSettingsWindows()\n        //     {\n        //         var adSetting =\n        //             CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Ads.AdSetting>(\"/Ads\");\n        //         AdsWindowEditor adWindow = GetWindow<AdsWindowEditor>(\"Ads Settings\");\n        //         adWindow._adSetting = adSetting;\n        //         if (adWindow == null)\n        //         {\n        //             Debug.LogError(\"Couldn't open the ads settings window!\");\n        //             return;\n        //         }\n        //\n        //         adWindow.minSize = new Vector2(275, 0);\n        //         adWindow.Show();\n        //         EditorGUIUtility.PingObject(adSetting);\n        //     }\n        //\n        //     private void OnGUI()\n        //     {\n        //         EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height),\n        //             GameDataEditor.ColorBackgroundRectWindowSunflower.ToColor());\n        //         GUI.contentColor = GameDataEditor.ColorTextContentWindowSunflower.ToColor();\n        //         GUI.backgroundColor = GameDataEditor.ColorContentWindowSunflower.ToColor();\n        //         if (_editor == null) _editor = UnityEditor.Editor.CreateEditor(_adSetting);\n        //\n        //         if (_editor == null)\n        //         {\n        //             EditorGUILayout.HelpBox(\"Couldn't create the settings resources editor.\",\n        //                 MessageType.Error);\n        //             return;\n        //         }\n        //\n        //         //    _editor.DrawHeader();\n        //         _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);\n        //         EditorGUILayout.BeginVertical(new GUIStyle { padding = new RectOffset(6, 3, 3, 3) });\n        //         _editor.OnInspectorGUI();\n        //\n        //         GUILayout.Space(10);\n        //         Handles.color = Color.black;\n        //         Handles.DrawAAPolyLine(3, new Vector3(0, GUILayoutUtility.GetLastRect().y + 10),\n        //             new Vector3(position.width, GUILayoutUtility.GetLastRect().y + 10));\n        //         GUILayout.Space(10);\n        //\n        //\n        //         EditorGUILayout.EndVertical();\n        //         EditorGUILayout.EndScrollView();\n        //     }\n        //\n        //     #region Applovin\n        //\n        //     private const string pathMax = \"/Ads/Applovin\";\n        //\n        //     [MenuItem(\"Sunflower/Ads/Applovin/Max Client\")]\n        //     public static void CreateMaxClient()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<MaxAdClient>(pathMax, \"max_ad_client\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Applovin/Max Banner\")]\n        //     public static void CreateMaxBanner()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<MaxBannerVariable>(pathMax, \"max_banner_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Applovin/Max Inter\")]\n        //     public static void CreateMaxInter()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<MaxInterVariable>(pathMax, \"max_inter_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Applovin/Max Reward\")]\n        //     public static void CreateMaxReward()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<MaxRewardVariable>(pathMax, \"max_reward_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Applovin/Max App Open\")]\n        //     public static void CreateMaxAppOpen()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<MaxAppOpenVariable>(pathMax,\n        //             \"max_app_open_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Applovin/Max Reward Inter\")]\n        //     public static void CreateMaxRewardInter()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<MaxRewardInterVariable>(pathMax,\n        //             \"max_reward_inter_variable\");\n        //     }\n        //\n        //     #endregion\n        //\n        //     #region Admob\n        //\n        //     private const string pathAdmob = \"/Ads/Admob\";\n        //\n        //     [MenuItem(\"Sunflower/Ads/Admob/Admob Client\")]\n        //     public static void CreateAdmobClient()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<AdmobAdClient>(pathAdmob, \"admob_ad_client\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Admob/Admob Banner\")]\n        //     public static void CreateAdmobBanner()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<AdmobBannerVariable>(pathAdmob,\n        //             \"admob_banner_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Admob/Admob Inter\")]\n        //     public static void CreateAdmobInter()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<AdmobInterVariable>(pathAdmob,\n        //             \"admob_inter_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Admob/Admob Reward\")]\n        //     public static void CreateAdmobReward()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<AdmobRewardVariable>(pathAdmob,\n        //             \"admob_reward_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Admob/Admob App Open\")]\n        //     public static void CreateAdmobAppOpen()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<AdmobAppOpenVariable>(pathAdmob,\n        //             \"admob_app_open_variable\");\n        //     }\n        //\n        //     [MenuItem(\"Sunflower/Ads/Admob/Admob Reward Inter\")]\n        //     public static void CreateAdmobRewardInter()\n        //     {\n        //         CreateAsset.CreateScriptableAssets<AdmobRewardInterVariable>(pathAdmob,\n        //             \"admob_reward_inter_variable\");\n        //     }\n        //\n        //     #endregion\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Advertising/Editor/AdsWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6fd65ccaee60423bbab98afe628d2016\ntimeCreated: 1695461341"
  },
  {
    "path": "VirtueSky/Advertising/Editor/Virtuesky.Sunflower.Advertising.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Advertising.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:abd57f653a468a04c8d4e281527ff293\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:0b6289df6f84a6f4b982ff72d23e0273\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Advertising/Editor/Virtuesky.Sunflower.Advertising.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: ea1af3c654880af4ca6bb44b012e055e\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: c0fa69d79e042904290c060082316cf1\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmobAdClient.cs",
    "content": "#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\n#endif\nusing VirtueSky.Core;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    public sealed class AdmobAdClient : AdClient\n    {\n        public AdmobAdClient(AdSetting _adSetting)\n        {\n            adSetting = _adSetting;\n        }\n\n        public override void Initialize()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n#if UNITY_IOS\n            // On Android, Unity is paused when displaying interstitial or rewarded video.\n            // This setting makes iOS behave consistently with Android.\n            MobileAds.SetiOSAppPauseOnBackground(true);         \n#endif\n\n            // When true all events raised by GoogleMobileAds will be raised\n            // on the Unity main thread. The default value is false.\n            // https://developers.google.com/admob/unity/quick-start#raise_ad_events_on_the_unity_main_thread\n            MobileAds.RaiseAdEventsOnUnityMainThread = true;\n\n            MobileAds.Initialize(initStatus =>\n            {\n                App.RunOnMainThread(() =>\n                {\n                    if (!adSetting.AdmobEnableTestMode) return;\n                    var configuration = new RequestConfiguration\n                        { TestDeviceIds = adSetting.AdmobDevicesTest };\n                    MobileAds.SetRequestConfiguration(configuration);\n                });\n            });\n            FirebaseAnalyticTrackingRevenue.autoTrackAdImpressionAdmob = adSetting.AutoTrackingAdImpressionAdmob;\n            adSetting.AdmobBannerVariable.Init();\n            adSetting.AdmobInterVariable.Init();\n            adSetting.AdmobRewardVariable.Init();\n            adSetting.AdmobRewardInterVariable.Init();\n            adSetting.AdmobAppOpenVariable.Init();\n            adSetting.AdmobNativeOverlayVariable.Init();\n\n            RegisterAppStateChange();\n            LoadInterstitial();\n            LoadRewarded();\n            LoadRewardedInterstitial();\n            LoadAppOpen();\n            LoadBanner();\n            LoadNativeOverlay();\n#endif\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        void RegisterAppStateChange()\n        {\n            GoogleMobileAds.Api.AppStateEventNotifier.AppStateChanged += OnAppStateChanged;\n        }\n\n        void OnAppStateChanged(GoogleMobileAds.Common.AppState state)\n        {\n            if (state == GoogleMobileAds.Common.AppState.Foreground && adSetting.AdmobAppOpenVariable.autoShow)\n            {\n                if (adSetting.UseAdmob) ShowAppOpen();\n            }\n        }\n#endif\n        public override void LoadBanner()\n        {\n            if (adSetting.AdmobBannerVariable == null) return;\n            adSetting.AdmobBannerVariable.Load();\n        }\n\n        public override void LoadInterstitial()\n        {\n            if (adSetting.AdmobInterVariable == null) return;\n            if (!adSetting.AdmobInterVariable.IsReady()) adSetting.AdmobInterVariable.Load();\n        }\n\n        public override void LoadRewarded()\n        {\n            if (adSetting.AdmobRewardVariable == null) return;\n            if (!adSetting.AdmobRewardVariable.IsReady()) adSetting.AdmobRewardVariable.Load();\n        }\n\n        public override void LoadRewardedInterstitial()\n        {\n            if (adSetting.AdmobRewardInterVariable == null) return;\n            if (!adSetting.AdmobRewardInterVariable.IsReady()) adSetting.AdmobRewardInterVariable.Load();\n        }\n\n        public override void LoadAppOpen()\n        {\n            if (adSetting.AdmobAppOpenVariable == null) return;\n            if (!adSetting.AdmobAppOpenVariable.IsReady()) adSetting.AdmobAppOpenVariable.Load();\n        }\n\n        public override void ShowAppOpen()\n        {\n            if (statusAppOpenFirstIgnore) adSetting.AdmobAppOpenVariable.Show();\n            statusAppOpenFirstIgnore = true;\n        }\n\n        public override void LoadNativeOverlay()\n        {\n            if (adSetting.AdmobNativeOverlayVariable == null) return;\n            if (!adSetting.AdmobNativeOverlayVariable.IsReady()) adSetting.AdmobNativeOverlayVariable.Load();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmobAdClient.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9dfd25949deb4dd5b2c3d85ef6e79929\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmobAdUnitVariable.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Ads\n{\n    public class AdmobAdUnitVariable : AdUnitVariable\n    {\n        [SerializeField] protected string androidId;\n        [SerializeField] protected string iOSId;\n        [NonSerialized] private string idRuntime = string.Empty;\n\n        public override bool IsShowing { get; internal set; }\n\n        public override string Id\n        {\n            get\n            {\n                if (idRuntime == String.Empty)\n                {\n#if UNITY_ANDROID\n                    return androidId;\n#elif UNITY_IOS\n                    return iOSId;\n#else\n                    return string.Empty;\n#endif\n                }\n\n                return idRuntime;\n            }\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!Application.isMobilePlatform || string.IsNullOrEmpty(Id) || AdStatic.IsRemoveAd ||\n                !IsReady()) return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        public void SetIdRuntime(string unitId)\n        {\n            idRuntime = unitId;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmobAdUnitVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 87d7f6324d01404eb012e525818f93de\ntimeCreated: 1728634495"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobAppOpenVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\nusing VirtueSky.Tracking;\n#endif\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdmobAppOpenVariable : AdmobAdUnitVariable\n    {\n        [Tooltip(\"Automatically show AppOpenAd when app status is changed\")]\n        public bool autoShow = false;\n\n        [Tooltip(\"Time between closing the previous full-screen ad and starting to show the app open ad - in seconds\")]\n        public float timeBetweenFullScreenAd = 2f;\n\n        public bool useTestId;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private AppOpenAd _appOpenAd;\n#endif\n        private DateTime _expireTime;\n\n        public override void Init()\n        {\n            if (useTestId)\n            {\n                GetUnitTest();\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n\n            Destroy();\n            AppOpenAd.Load(Id, new AdRequest(), OnAdLoadCallback);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            return _appOpenAd != null && _appOpenAd.CanShowAd() && DateTime.Now < _expireTime &&\n                   (DateTime.Now - AdStatic.AdClosingTime).TotalSeconds > timeBetweenFullScreenAd;\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _appOpenAd.Show();\n#endif\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_appOpenAd == null) return;\n            _appOpenAd.Destroy();\n            _appOpenAd = null;\n#endif\n        }\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private void OnAdLoadCallback(AppOpenAd ad, LoadAdError error)\n        {\n            // if error is not null, the load request failed.\n            if (error != null || ad == null)\n            {\n                OnAdFailedToLoad(error);\n                return;\n            }\n\n            _appOpenAd = ad;\n            _appOpenAd.OnAdPaid += OnAdPaided;\n            _appOpenAd.OnAdFullScreenContentClosed += OnAdClosed;\n            _appOpenAd.OnAdFullScreenContentFailed += OnAdFailedToShow;\n            _appOpenAd.OnAdFullScreenContentOpened += OnAdOpening;\n            _appOpenAd.OnAdClicked += OnAdClicked;\n            OnAdLoaded();\n\n            // App open ads can be preloaded for up to 4 hours.\n            _expireTime = DateTime.Now + TimeSpan.FromHours(4);\n        }\n\n        private void OnAdClicked()\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        private void OnAdOpening()\n        {\n            AdStatic.waitAppOpenDisplayedAction?.Invoke();\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToShow(AdError obj)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(obj.GetMessage());\n        }\n\n        private void OnAdClosed()\n        {\n            AdStatic.waitAppOpenClosedAction?.Invoke();\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n            Destroy();\n        }\n\n        private void OnAdPaided(AdValue value)\n        {\n            paidedCallback?.Invoke(value.Value / 1000000f,\n                \"Admob\",\n                Id,\n                \"AppOpenAd\", AdMediation.Admob.ToString());\n        }\n\n        private void OnAdLoaded()\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToLoad(LoadAdError error)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(error.GetMessage());\n        }\n\n#endif\n\n        [ContextMenu(\"Get Id test\")]\n        void GetUnitTest()\n        {\n#if UNITY_ANDROID\n            androidId = \"ca-app-pub-3940256099942544/9257395921\";\n#elif UNITY_IOS\n            iOSId = \"ca-app-pub-3940256099942544/5575463023\";\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobAppOpenVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bcb8d284edcd4713bbddf482061bd612\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobBannerVariable.cs",
    "content": "using System;\nusing System.Collections;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\nusing VirtueSky.Tracking;\n#endif\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdmobBannerVariable : AdmobAdUnitVariable\n    {\n        public AdsSize size = AdsSize.Adaptive;\n        public AdsPosition position = AdsPosition.Bottom;\n        public bool useCollapsible;\n        public bool useTestId;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private BannerView _bannerView;\n#endif\n\n        private readonly WaitForSeconds _waitBannerReload = new WaitForSeconds(5f);\n        private IEnumerator _reload;\n        private bool _isBannerShowing;\n        private bool _previousBannerShowStatus;\n\n        public override void Init()\n        {\n            if (useTestId)\n            {\n                GetUnitTest();\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            Destroy();\n            _bannerView = new BannerView(Id, ConvertSize(), ConvertPosition());\n            _bannerView.OnAdFullScreenContentClosed += OnAdClosed;\n            _bannerView.OnBannerAdLoadFailed += OnAdFailedToLoad;\n            _bannerView.OnBannerAdLoaded += OnAdLoaded;\n            _bannerView.OnAdFullScreenContentOpened += OnAdOpening;\n            _bannerView.OnAdPaid += OnAdPaided;\n            _bannerView.OnAdClicked += OnAdClicked;\n            var adRequest = new AdRequest();\n            if (useCollapsible)\n            {\n                adRequest.Extras.Add(\"collapsible\", ConvertPlacementCollapsible());\n            }\n\n            _bannerView.LoadAd(adRequest);\n#endif\n        }\n\n        public bool IsCollapsible()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_bannerView == null) return false;\n            return _bannerView.IsCollapsible();\n#else\n            return false;\n#endif\n        }\n\n        void OnWaitAppOpenClosed()\n        {\n            if (_previousBannerShowStatus)\n            {\n                _previousBannerShowStatus = false;\n                Show();\n            }\n        }\n\n        void OnWaitAppOpenDisplayed()\n        {\n            _previousBannerShowStatus = _isBannerShowing;\n            if (_isBannerShowing) HideBanner();\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            return _bannerView != null;\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _isBannerShowing = true;\n            IsShowing = true;\n            AdStatic.waitAppOpenClosedAction = OnWaitAppOpenClosed;\n            AdStatic.waitAppOpenDisplayedAction = OnWaitAppOpenDisplayed;\n            if (_bannerView == null)\n            {\n                Load();\n            }\n\n            _bannerView.Show();\n#endif\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_bannerView == null) return;\n            _isBannerShowing = false;\n            IsShowing = false;\n            AdStatic.waitAppOpenClosedAction = null;\n            AdStatic.waitAppOpenDisplayedAction = null;\n            _bannerView.Destroy();\n            _bannerView = null;\n#endif\n        }\n\n        public override void HideBanner()\n        {\n            base.HideBanner();\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _isBannerShowing = false;\n            IsShowing = false;\n            if (_bannerView != null) _bannerView.Hide();\n#endif\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        public AdSize ConvertSize()\n        {\n            switch (size)\n            {\n                case AdsSize.Adaptive:\n                    return AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(\n                        AdSize.FullWidth);\n                case AdsSize.MediumRectangle: return AdSize.MediumRectangle;\n                case AdsSize.Leaderboard: return AdSize.Leaderboard;\n                case AdsSize.IABBanner: return AdSize.IABBanner;\n                //case BannerSize.SmartBanner: return AdSize.SmartBanner;\n                default: return AdSize.Banner;\n            }\n        }\n\n        public AdPosition ConvertPosition()\n        {\n            switch (position)\n            {\n                case AdsPosition.Top: return AdPosition.Top;\n                case AdsPosition.Bottom: return AdPosition.Bottom;\n                case AdsPosition.TopLeft: return AdPosition.TopLeft;\n                case AdsPosition.TopRight: return AdPosition.TopRight;\n                case AdsPosition.BottomLeft: return AdPosition.BottomLeft;\n                case AdsPosition.BottomRight: return AdPosition.BottomRight;\n                default: return AdPosition.Bottom;\n            }\n        }\n\n        public string ConvertPlacementCollapsible()\n        {\n            if (position == AdsPosition.Top)\n            {\n                return \"top\";\n            }\n            else if (position == AdsPosition.Bottom)\n            {\n                return \"bottom\";\n            }\n\n            return \"bottom\";\n        }\n\n        private void OnAdPaided(AdValue value)\n        {\n            paidedCallback?.Invoke(value.Value / 1000000f,\n                \"Admob\",\n                Id,\n                \"BannerAd\", AdMediation.Admob.ToString());\n        }\n\n        private void OnAdClicked()\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        private void OnAdOpening()\n        {\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdLoaded()\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToLoad(LoadAdError error)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(error.GetMessage());\n            if (_reload != null) App.StopCoroutine(_reload);\n            _reload = DelayBannerReload();\n            App.StartCoroutine(_reload);\n        }\n\n        private void OnAdClosed()\n        {\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n        }\n\n        private IEnumerator DelayBannerReload()\n        {\n            yield return _waitBannerReload;\n            Load();\n        }\n#endif\n\n        [ContextMenu(\"Get Id test\")]\n        void GetUnitTest()\n        {\n#if UNITY_ANDROID\n            androidId = \"ca-app-pub-3940256099942544/6300978111\";\n#elif UNITY_IOS\n            iOSId = \"ca-app-pub-3940256099942544/2934735716\";\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobBannerVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 87ac8fce1cfb4b09805621d419310150\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobInterVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\nusing VirtueSky.Tracking;\n#endif\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdmobInterVariable : AdmobAdUnitVariable\n    {\n        public bool useTestId;\n        [NonSerialized] internal Action completedCallback;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private InterstitialAd _interstitialAd;\n#endif\n        public override void Init()\n        {\n            if (useTestId)\n            {\n                GetUnitTest();\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n\n            Destroy();\n            InterstitialAd.Load(Id, new AdRequest(), AdLoadCallback);\n\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            return _interstitialAd != null && _interstitialAd.CanShowAd();\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _interstitialAd.Show();\n#endif\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_interstitialAd == null) return;\n            _interstitialAd.Destroy();\n            _interstitialAd = null;\n#endif\n        }\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private void AdLoadCallback(InterstitialAd ad, LoadAdError error)\n        {\n            // if error is not null, the load request failed.\n            if (error != null || ad == null)\n            {\n                OnAdFailedToLoad(error);\n                return;\n            }\n\n            _interstitialAd = ad;\n            _interstitialAd.OnAdPaid += OnAdPaided;\n            _interstitialAd.OnAdFullScreenContentClosed += OnAdClosed;\n            _interstitialAd.OnAdFullScreenContentFailed += OnAdFailedToShow;\n            _interstitialAd.OnAdFullScreenContentOpened += OnAdOpening;\n            _interstitialAd.OnAdClicked += OnAdClicked;\n            OnAdLoaded();\n        }\n\n        private void OnAdClicked()\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        private void OnAdOpening()\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToShow(AdError error)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(error.GetMessage());\n        }\n\n        private void OnAdClosed()\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref completedCallback);\n            OnClosedAdEvent?.Invoke();\n            Destroy();\n        }\n\n        private void OnAdPaided(AdValue value)\n        {\n            paidedCallback?.Invoke(value.Value / 1000000f,\n                \"Admob\",\n                Id,\n                \"InterstitialAd\", AdMediation.Admob.ToString());\n        }\n\n        private void OnAdLoaded()\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToLoad(LoadAdError error)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(error.GetMessage());\n        }\n#endif\n\n        [ContextMenu(\"Get Id test\")]\n        void GetUnitTest()\n        {\n#if UNITY_ANDROID\n            androidId = \"ca-app-pub-3940256099942544/1033173712\";\n#elif UNITY_IOS\n            iOSId = \"ca-app-pub-3940256099942544/4411468910\";\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobInterVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b04367785ed74ad986055150f5961286\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobNativeOverlayVariable.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Utils;\nusing System.Collections;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\n#endif\nusing VirtueSky.Core;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdmobNativeOverlayVariable : AdmobAdUnitVariable\n    {\n        public enum NativeTemplate\n        {\n            Small,\n            Medium\n        }\n\n        [SerializeField] private bool useTestId;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        [HeaderLine(\"NativeAd Options\", false)] [SerializeField]\n        private AdChoicesPlacement adChoicesPlacement;\n\n        [SerializeField] private MediaAspectRatio mediaAspectRatio;\n        [SerializeField] private VideoOptions videoOptions;\n\n\n        [HeaderLine(\"NativeAd Style\", false)] public NativeTemplate nativeTemplate;\n        public Color mainBackgroundColor = Color.white;\n        public AdsSize adsSize = AdsSize.MediumRectangle;\n        public AdsPosition adsPosition = AdsPosition.Bottom;\n\n        //  public NativeTemplateFontStyle nativeTemplateFontStyle;\n        private NativeOverlayAd _nativeOverlayAd;\n#endif\n        private readonly WaitForSeconds _waitReload = new WaitForSeconds(5f);\n        private IEnumerator _reload;\n\n        /// <summary>\n        /// Init ads and register callback tracking\n        /// </summary>\n        public override void Init()\n        {\n            if (useTestId)\n            {\n                GetUnitTest();\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n#endif\n        }\n\n        /// <summary>\n        /// Load ads\n        /// </summary>\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            if (_nativeOverlayAd != null)\n            {\n                Destroy();\n            }\n\n            var adRequest = new AdRequest();\n            var option = new NativeAdOptions\n            {\n                AdChoicesPlacement = adChoicesPlacement,\n                MediaAspectRatio = mediaAspectRatio,\n                VideoOptions = videoOptions\n            };\n            NativeOverlayAd.Load(Id, adRequest, option, AdLoadCallback);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            return _nativeOverlayAd != null;\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd != null)\n                _nativeOverlayAd.Show();\n#endif\n        }\n\n        /// <summary>\n        /// destroy native overlay ads\n        /// </summary>\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd != null)\n            {\n                _nativeOverlayAd.Destroy();\n                _nativeOverlayAd = null;\n            }\n#endif\n        }\n\n        /// <summary>\n        /// Hide native overlay ads\n        /// </summary>\n        public void Hide()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd != null) _nativeOverlayAd.Hide();\n#endif\n        }\n\n\n        /// <summary>\n        /// Render native overlay ads default\n        /// </summary>\n        public void RenderAd()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd == null) return;\n            _nativeOverlayAd.RenderTemplate(Style(), ConvertSize(), ConvertPosition(adsPosition));\n#endif\n        }\n\n        /// <summary>\n        /// Render native ads according to uiElement, use canvas overlay\n        /// </summary>\n        /// <param name=\"uiElement\">RectTransform of uiElement, used to determine position for native overlay ads</param>\n        public void RenderAd(RectTransform uiElement)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd == null) return;\n            (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement);\n            _nativeOverlayAd.RenderTemplate(Style(), admobX, admobY);\n#endif\n        }\n\n        /// <summary>\n        /// Render native ads according to uiElement, use canvas overlay\n        /// </summary>\n        /// <param name=\"uiElement\">RectTransform of uiElement, used to determine position for native overlay ads</param>\n        /// <param name=\"width\">Custom width for native overlay ads</param>\n        /// <param name=\"height\">Custom height for native overlay ads</param>\n        public void RenderAd(RectTransform uiElement, int width, int height)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd == null) return;\n            (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement);\n            _nativeOverlayAd.RenderTemplate(Style(), new AdSize(width, height), admobX, admobY);\n#endif\n        }\n\n        /// <summary>\n        /// Render native ads according to uiElement, use canvas screen-space camera\n        /// Can use position and size of uiElement for native overlay ads\n        /// </summary>\n        /// <param name=\"uiElement\">RectTransform of uiElement, used to determine position for native overlay ads</param>\n        /// <param name=\"camera\">Camera render uiElement</param>\n        public void RenderAd(RectTransform uiElement, Camera camera, bool useSizeUiElement = true)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd == null) return;\n            (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement, camera);\n            if (useSizeUiElement)\n            {\n                _nativeOverlayAd?.RenderTemplate(Style(),\n                    new AdSize((int)uiElement.rect.width, (int)uiElement.rect.height), admobX, admobY);\n            }\n            else\n            {\n                _nativeOverlayAd?.RenderTemplate(Style(), admobX, admobY);\n            }\n#endif\n        }\n\n        /// <summary>\n        /// Render native ads according to uiElement, use canvas screen-space camera\n        /// Can use position of uiElement and custom size for native overlay ads\n        /// </summary>\n        /// <param name=\"uiElement\">RectTransform of uiElement, used to determine position for native overlay ads</param>\n        /// <param name=\"camera\">Camera render uiElement</param>\n        /// <param name=\"width\">Custom width for native overlay ads</param>\n        /// <param name=\"height\">Custom height for native overlay ads</param>\n        public void RenderAd(RectTransform uiElement, Camera camera, int width, int height)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_nativeOverlayAd == null) return;\n            (int admobX, int admobY) = ConvertUiElementPosToNativeAdsPos(uiElement, camera, width, height);\n            _nativeOverlayAd?.RenderTemplate(Style(), new AdSize(width, height), admobX, admobY);\n#endif\n        }\n\n        (int, int) ConvertUiElementPosToNativeAdsPos(RectTransform uiElement, Camera camera, int width, int height)\n        {\n            var worldPosition = uiElement.TransformPoint(uiElement.position);\n            Vector2 screenPosition = camera.WorldToScreenPoint(worldPosition);\n\n            float dpi = Screen.dpi / 160f;\n            var admobX = (int)((screenPosition.x - width / 2) / dpi);\n            var admobY = (int)(((Screen.height - (int)screenPosition.y) - height / 2) / dpi);\n            return (admobX, admobY);\n        }\n\n        (int, int) ConvertUiElementPosToNativeAdsPos(RectTransform uiElement, Camera camera)\n        {\n            var worldPosition = uiElement.TransformPoint(uiElement.position);\n            Vector2 screenPosition = camera.WorldToScreenPoint(worldPosition);\n\n            float dpi = Screen.dpi / 160f;\n            var admobX = (int)((screenPosition.x - (int)uiElement.rect.width / 2) / dpi);\n            var admobY = (int)(((Screen.height - (int)screenPosition.y) - (int)uiElement.rect.height / 2) / dpi);\n            return (admobX, admobY);\n        }\n\n        (int, int) ConvertUiElementPosToNativeAdsPos(RectTransform uiElement)\n        {\n            var screenPosition = uiElement.ToWorldPosition();\n            float dpi = Screen.dpi / 160f;\n            var admobX = (int)(screenPosition.x / dpi);\n            var admobY = (int)((Screen.height - (int)screenPosition.y) / dpi);\n            return (admobX, admobY);\n        }\n\n        public void SetPosition(AdsPosition adsPosition)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _nativeOverlayAd.SetTemplatePosition(ConvertPosition(adsPosition));\n#endif\n        }\n\n        public void SetPosition(int x, int y)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _nativeOverlayAd.SetTemplatePosition(x, y);\n#endif\n        }\n\n        public void SetPosition(RectTransform uiElement)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            (int x, int y) = ConvertUiElementPosToNativeAdsPos(uiElement);\n            _nativeOverlayAd.SetTemplatePosition(x, y);\n#endif\n        }\n\n        public void SetPosition(RectTransform uiElement, Camera camera)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            (int x, int y) = ConvertUiElementPosToNativeAdsPos(uiElement, camera);\n            _nativeOverlayAd.SetTemplatePosition(x, y);\n#endif\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        public NativeTemplateStyle Style()\n        {\n            return new NativeTemplateStyle\n            {\n                TemplateId = nativeTemplate.ToString().ToLower(),\n                MainBackgroundColor = mainBackgroundColor,\n                // CallToActionText = new NativeTemplateTextStyle\n                // {\n                //     BackgroundColor = Color.green,\n                //     TextColor = Color.white,\n                //     FontSize = 9,\n                //     Style = nativeTemplateFontStyle\n                // }\n            };\n        }\n\n        AdPosition ConvertPosition(AdsPosition _adsPosition)\n        {\n            return _adsPosition switch\n            {\n                AdsPosition.Top => AdPosition.Top,\n                AdsPosition.Bottom => AdPosition.Bottom,\n                AdsPosition.TopLeft => AdPosition.TopLeft,\n                AdsPosition.TopRight => AdPosition.TopRight,\n                AdsPosition.BottomLeft => AdPosition.BottomLeft,\n                AdsPosition.BottomRight => AdPosition.BottomRight,\n                _ => AdPosition.Center\n            };\n        }\n\n        AdSize ConvertSize()\n        {\n            return adsSize switch\n            {\n                AdsSize.Banner => AdSize.Banner,\n                AdsSize.MediumRectangle => AdSize.MediumRectangle,\n                AdsSize.IABBanner => AdSize.IABBanner,\n                AdsSize.Leaderboard => AdSize.Leaderboard,\n                _ => AdSize.MediumRectangle,\n            };\n        }\n\n        private void AdLoadCallback(NativeOverlayAd ad, LoadAdError error)\n        {\n            if (error != null || ad == null)\n            {\n                OnAdFailedToLoad(error);\n                return;\n            }\n\n            _nativeOverlayAd = ad;\n            _nativeOverlayAd.OnAdPaid += OnAdPaided;\n            _nativeOverlayAd.OnAdClicked += OnAdClicked;\n            _nativeOverlayAd.OnAdFullScreenContentOpened += OnAdOpening;\n            _nativeOverlayAd.OnAdFullScreenContentClosed += OnAdClosed;\n            OnAdLoaded();\n        }\n\n        private void OnAdLoaded()\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdClosed()\n        {\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n        }\n\n        private void OnAdOpening()\n        {\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdClicked()\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        private void OnAdPaided(AdValue value)\n        {\n            paidedCallback?.Invoke(value.Value / 1000000f,\n                \"Admob\",\n                Id,\n                \"NativeOverlayAd\", AdMediation.Admob.ToString());\n        }\n\n        private void OnAdFailedToLoad(LoadAdError error)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(error.GetMessage());\n            if (_reload != null) App.StopCoroutine(_reload);\n            _reload = DelayReload();\n            App.StartCoroutine(_reload);\n        }\n\n        private IEnumerator DelayReload()\n        {\n            yield return _waitReload;\n            Load();\n        }\n#endif\n        [ContextMenu(\"Get Id test\")]\n        void GetUnitTest()\n        {\n#if UNITY_ANDROID\n            androidId = \"ca-app-pub-3940256099942544/2247696110\";\n#elif UNITY_IOS\n            iOSId = \"ca-app-pub-3940256099942544/3986624511\";\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobNativeOverlayVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8b15194a160445d694586481bfdc91cb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardInterVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\n#endif\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdmobRewardInterVariable : AdmobAdUnitVariable\n    {\n        public bool useTestId;\n        [NonSerialized] internal Action completedCallback;\n        [NonSerialized] internal Action skippedCallback;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private RewardedInterstitialAd _rewardedInterstitialAd;\n#endif\n        public override void Init()\n        {\n            if (useTestId)\n            {\n                GetUnitTest();\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n#endif\n        }\n\n        public bool IsEarnRewarded { get; private set; }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (string.IsNullOrEmpty(Id)) return;\n            Destroy();\n            RewardedInterstitialAd.Load(Id, new AdRequest(), OnAdLoadCallback);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            return _rewardedInterstitialAd != null && _rewardedInterstitialAd.CanShowAd();\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _rewardedInterstitialAd.Show(UserEarnedRewardCallback);\n#endif\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n            skippedCallback = null;\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!UnityEngine.Application.isMobilePlatform || string.IsNullOrEmpty(Id) || !IsReady())\n                return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_rewardedInterstitialAd == null) return;\n            _rewardedInterstitialAd.Destroy();\n            _rewardedInterstitialAd = null;\n            IsEarnRewarded = false;\n#endif\n        }\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private void OnAdLoadCallback(RewardedInterstitialAd ad, LoadAdError error)\n        {\n            // if error is not null, the load request failed.\n            if (error != null || ad == null)\n            {\n                OnAdFailedToLoad(error);\n                return;\n            }\n\n            _rewardedInterstitialAd = ad;\n            _rewardedInterstitialAd.OnAdFullScreenContentClosed += OnAdClosed;\n            _rewardedInterstitialAd.OnAdFullScreenContentOpened += OnAdOpening;\n            _rewardedInterstitialAd.OnAdFullScreenContentFailed += OnAdFailedToShow;\n            _rewardedInterstitialAd.OnAdPaid += OnAdPaided;\n            _rewardedInterstitialAd.OnAdClicked += OnAdClicked;\n            OnAdLoaded();\n        }\n\n        private void OnAdClicked()\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToLoad(LoadAdError error)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(error.GetMessage());\n        }\n\n        private void OnAdLoaded()\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdPaided(AdValue value)\n        {\n            paidedCallback?.Invoke(value.Value / 1000000f,\n                \"Admob\",\n                Id,\n                \"RewardedInterstitialAd\", AdMediation.Admob.ToString());\n        }\n\n        private void OnAdFailedToShow(AdError error)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(error.GetMessage());\n        }\n\n        private void OnAdOpening()\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdClosed()\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n            if (IsEarnRewarded)\n            {\n                Common.CallActionAndClean(ref completedCallback);\n                _rewardedInterstitialAd.Destroy();\n                return;\n            }\n\n            Common.CallActionAndClean(ref skippedCallback);\n            _rewardedInterstitialAd.Destroy();\n        }\n\n        private void UserEarnedRewardCallback(Reward reward)\n        {\n            IsEarnRewarded = true;\n        }\n#endif\n\n        [ContextMenu(\"Get Id test\")]\n        void GetUnitTest()\n        {\n#if UNITY_ANDROID\n            androidId = \"ca-app-pub-3940256099942544/5354046379\";\n#elif UNITY_IOS\n            iOSId = \"ca-app-pub-3940256099942544/6978759866\";\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardInterVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ddd2127be5434974aa775c9d809bc25f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\n#endif\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdmobRewardVariable : AdmobAdUnitVariable\n    {\n        public bool useTestId;\n        [NonSerialized] internal Action completedCallback;\n        [NonSerialized] internal Action skippedCallback;\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private RewardedAd _rewardedAd;\n#endif\n        public override void Init()\n        {\n            if (useTestId)\n            {\n                GetUnitTest();\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n#endif\n        }\n\n        public bool IsEarnRewarded { get; private set; }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (string.IsNullOrEmpty(Id)) return;\n            Destroy();\n            RewardedAd.Load(Id, new AdRequest(), AdLoadCallback);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            return _rewardedAd != null && _rewardedAd.CanShowAd();\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            _rewardedAd.Show(UserRewardEarnedCallback);\n#endif\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!UnityEngine.Application.isMobilePlatform || string.IsNullOrEmpty(Id) || !IsReady())\n                return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n            skippedCallback = null;\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n            if (_rewardedAd == null) return;\n            _rewardedAd.Destroy();\n            _rewardedAd = null;\n            IsEarnRewarded = false;\n#endif\n        }\n\n#if VIRTUESKY_ADS && VIRTUESKY_ADMOB\n        private void AdLoadCallback(RewardedAd ad, LoadAdError error)\n        {\n            // if error is not null, the load request failed.\n            if (error != null || ad == null)\n            {\n                OnAdFailedToLoad(error);\n                return;\n            }\n\n            _rewardedAd = ad;\n            _rewardedAd.OnAdFullScreenContentClosed += OnAdClosed;\n            _rewardedAd.OnAdFullScreenContentFailed += OnAdFailedToShow;\n            _rewardedAd.OnAdFullScreenContentOpened += OnAdOpening;\n            _rewardedAd.OnAdPaid += OnAdPaided;\n            _rewardedAd.OnAdClicked += OnAdClicked;\n            OnAdLoaded();\n        }\n\n        private void OnAdClicked()\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        private void OnAdPaided(AdValue value)\n        {\n            paidedCallback?.Invoke(value.Value / 1000000f,\n                \"Admob\",\n                Id,\n                \"RewardedAd\", AdMediation.Admob.ToString());\n        }\n\n        private void OnAdOpening()\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToShow(AdError obj)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(obj.GetMessage());\n        }\n\n        private void OnAdClosed()\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n            if (IsEarnRewarded)\n            {\n                Common.CallActionAndClean(ref completedCallback);\n                Destroy();\n                return;\n            }\n\n            Common.CallActionAndClean(ref skippedCallback);\n            Destroy();\n        }\n\n        private void OnAdLoaded()\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdFailedToLoad(LoadAdError error)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(error.GetMessage());\n        }\n\n        private void UserRewardEarnedCallback(Reward reward)\n        {\n            IsEarnRewarded = true;\n        }\n#endif\n\n        [ContextMenu(\"Get Id test\")]\n        void GetUnitTest()\n        {\n#if UNITY_ANDROID\n            androidId = \"ca-app-pub-3940256099942544/5224354917\";\n#elif UNITY_IOS\n            iOSId = \"ca-app-pub-3940256099942544/1712485313\";\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable/AdmobRewardVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0199f7cf7b5f44cfa63f780b9ff50857\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob/AdmodUnitVariable.meta",
    "content": "fileFormatVersion: 2\nguid: 5a8d9ff9a56c4478887d3a9190da2563\ntimeCreated: 1695462336"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Admob.meta",
    "content": "fileFormatVersion: 2\nguid: 488c040c267923f4e91f3c963c4e9536\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdClient.cs",
    "content": "using VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    public abstract class AdClient\n    {\n        protected AdSetting adSetting;\n        protected bool statusAppOpenFirstIgnore;\n\n        // public AdClient(AdSetting _adSetting)\n        // {\n        //     adSetting = _adSetting;\n        // }\n\n        public void SetupAdSetting(AdSetting _adSetting)\n        {\n            this.adSetting = _adSetting;\n        }\n\n        public abstract void Initialize();\n        public abstract void LoadBanner();\n        public abstract void LoadInterstitial();\n        public abstract void LoadRewarded();\n        public abstract void LoadRewardedInterstitial();\n        public abstract void LoadAppOpen();\n        public abstract void ShowAppOpen();\n\n        //Currently, native overlay ads is only available for admob.\n        public abstract void LoadNativeOverlay();\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdClient.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7af305bf9c13403badeef5393ca8283a\ntimeCreated: 1695566887"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdInfo.cs",
    "content": "namespace VirtueSky.Ads\n{\n    public class AdsInfo\n    {\n        public string AdUnitId { get; private set; }\n        public string AdFormat { get; private set; }\n        public string Placement { get; private set; }\n        public string AdNetwork { get; private set; }\n        public double Revenue { get; private set; }\n        public string AdMediation { get; private set; }\n        public string AuctionId { get; private set; }\n        \n#if VIRTUESKY_APPLOVIN\n        public AdsInfo(MaxSdkBase.AdInfo info)\n        {\n            AdUnitId = info.AdUnitIdentifier;\n            AdFormat = info.AdFormat;\n            Placement = info.Placement;\n            AdNetwork = info.NetworkName;\n            Revenue = info.Revenue;\n            AdMediation = Ads.AdMediation.AppLovin.ToString();\n            AuctionId = \"\";\n        }    \n#endif\n\n#if VIRTUESKY_LEVELPLAY\n        public AdsInfo(Unity.Services.LevelPlay.LevelPlayAdInfo info)\n        {\n            AdUnitId = info.AdUnitId;\n            AdFormat = info.AdFormat;\n            Placement = info.PlacementName;\n            AdNetwork = info.AdNetwork;\n            Revenue = (double)info.Revenue;\n            AdMediation = Ads.AdMediation.LevelPlay.ToString();\n            AuctionId = info.AuctionId;\n        }\n#endif\n        \n        public AdsInfo(string adUnitId, string adFormat, string placement, string adNetwork, double revenue, string adMediation, string auctionId)\n        {\n            AdUnitId = adUnitId;\n            AdFormat = adFormat;\n            Placement = placement;\n            AdNetwork = adNetwork;\n            Revenue = revenue;\n            AdMediation = adMediation;\n            AuctionId = auctionId;\n        }\n    }\n    \n    public class AdsError\n    {\n        public int ErrorCode { get; private set; }\n        public string ErrorMessage { get; private set; }\n        \n#if VIRTUESKY_APPLOVIN\n        public AdsError(MaxSdkBase.ErrorInfo info)\n        {\n            ErrorCode = (int)info.Code;\n            ErrorMessage = info.Message;\n        }\n#endif\n\n#if VIRTUESKY_LEVELPLAY\n        public AdsError(Unity.Services.LevelPlay.LevelPlayAdError adError)\n        {\n            ErrorCode = adError.ErrorCode;\n            ErrorMessage = adError.ErrorMessage;\n        }\n#endif\n\n#if VIRTUESKY_ADMOB\n        public AdsError(GoogleMobileAds.Api.AdError adError)\n        {\n            ErrorCode = adError.GetCode();\n            ErrorMessage = adError.GetMessage();\n        }\n#endif\n        public AdsError(int errorCode, string errorMessage)\n        {\n            ErrorCode = errorCode;\n            ErrorMessage = errorMessage;\n        }\n\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdInfo.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 12c07896615a460a871b51f30257302f\ntimeCreated: 1776757990"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdSetting.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.Serialization;\nusing VirtueSky.Inspector;\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\n\n\nnamespace VirtueSky.Ads\n{\n    [EditorIcon(\"icon_scriptable\")]\n    public class AdSetting : ScriptableObject\n    {\n        [Range(5, 100), SerializeField] private float adCheckingInterval = 8f;\n\n        [Range(5, 100), SerializeField] private float adLoadingInterval = 15f;\n\n        [SerializeField] private bool useAppLovin = true;\n        [SerializeField] private bool useAdmob;\n        [SerializeField] private bool useLevelPlay;\n        [SerializeField] private bool enableTrackAdRevenue = true;\n\n        [Tooltip(\"Install google-mobile-ads sdk to use GDPR\"), SerializeField]\n        private bool enableGDPR;\n\n        [SerializeField] private bool enableGDPRTestMode;\n        public float AdCheckingInterval => adCheckingInterval;\n        public float AdLoadingInterval => adLoadingInterval;\n        public bool UseAppLovin => useAppLovin;\n        public bool UseAdmob => useAdmob;\n        public bool UseLevelPlay => useLevelPlay;\n        public bool EnableTrackAdRevenue => enableTrackAdRevenue;\n        public bool EnableGDPR => enableGDPR;\n        public bool EnableGDPRTestMode => enableGDPRTestMode;\n\n        #region AppLovin\n\n        [TextArea, SerializeField] private string sdkKey;\n        [SerializeField] private MaxBannerVariable maxBannerVariable;\n        [SerializeField] private MaxInterVariable maxInterVariable;\n        [SerializeField] private MaxRewardVariable maxRewardVariable;\n        [SerializeField] private MaxAppOpenVariable maxAppOpenVariable;\n\n        public string SdkKey => sdkKey;\n        public MaxBannerVariable MaxBannerVariable => maxBannerVariable;\n        public MaxInterVariable MaxInterVariable => maxInterVariable;\n        public MaxRewardVariable MaxRewardVariable => maxRewardVariable;\n        public MaxAppOpenVariable MaxAppOpenVariable => maxAppOpenVariable;\n\n        #endregion\n\n        #region Admob\n\n        // [HeaderLine(\"Admob\")] \n        [SerializeField] private AdmobBannerVariable admobBannerVariable;\n        [SerializeField] private AdmobInterVariable admobInterVariable;\n        [SerializeField] private AdmobRewardVariable admobRewardVariable;\n        [SerializeField] private AdmobRewardInterVariable admobRewardInterVariable;\n        [SerializeField] private AdmobAppOpenVariable admobAppOpenVariable;\n        [SerializeField] private AdmobNativeOverlayVariable admobNativeOverlayVariable;\n\n        [Tooltip(\n             \"If you enable and connect admob with firebase, ad_impression will be automatically tracked. If you disable and disconnect admob with firebase, ad_impression will be tracked manually.\"),\n         SerializeField]\n        private bool autoTrackingAdImpressionAdmob = true;\n\n        [SerializeField] private bool admobEnableTestMode;\n        [SerializeField] private List<string> admobDevicesTest;\n        public AdmobBannerVariable AdmobBannerVariable => admobBannerVariable;\n        public AdmobInterVariable AdmobInterVariable => admobInterVariable;\n        public AdmobRewardVariable AdmobRewardVariable => admobRewardVariable;\n        public AdmobRewardInterVariable AdmobRewardInterVariable => admobRewardInterVariable;\n        public AdmobAppOpenVariable AdmobAppOpenVariable => admobAppOpenVariable;\n        public AdmobNativeOverlayVariable AdmobNativeOverlayVariable => admobNativeOverlayVariable;\n        public bool AdmobEnableTestMode => admobEnableTestMode;\n        public bool AutoTrackingAdImpressionAdmob => autoTrackingAdImpressionAdmob;\n\n        public List<string> AdmobDevicesTest => admobDevicesTest;\n\n        #endregion\n\n        #region LevelPlay\n\n        [SerializeField] private string androidAppKey;\n        [SerializeField] private string iOSAppKey;\n        [SerializeField] private bool useTestAppKey;\n\n        [SerializeField] private LevelPlayBannerVariable levelPlayBannerVariable;\n        [SerializeField] private LevelPlayInterVariable levelPlayInterVariable;\n        [SerializeField] private LevelPlayRewardVariable levelPlayRewardVariable;\n\n        public string AndroidAppKey\n        {\n            get => androidAppKey;\n            set => androidAppKey = value;\n        }\n\n        public string IosAppKey\n        {\n            get => iOSAppKey;\n            set => iOSAppKey = value;\n        }\n\n        public string AppKey\n        {\n            get\n            {\n#if UNITY_ANDROID\n                return androidAppKey;\n#elif UNITY_IOS\n                return iOSAppKey;\n#else\n                return string.Empty;\n#endif\n            }\n            set\n            {\n#if UNITY_ANDROID\n                androidAppKey = value;\n#elif UNITY_IOS\n                iOSAppKey = value;\n#endif\n            }\n        }\n\n        public bool UseTestAppKey => useTestAppKey;\n        public LevelPlayBannerVariable LevelPlayBannerVariable => levelPlayBannerVariable;\n        public LevelPlayInterVariable LevelPlayInterVariable => levelPlayInterVariable;\n        public LevelPlayRewardVariable LevelPlayRewardVariable => levelPlayRewardVariable;\n\n        #endregion\n    }\n\n    public enum AdMediation\n    {\n        AppLovin,\n        Admob,\n        LevelPlay\n    }\n\n    public enum AdsPosition\n    {\n        Top = 1,\n        Bottom = 0,\n        TopLeft = 2,\n        TopRight = 3,\n        BottomLeft = 4,\n        BottomRight = 5,\n        Center = 6,\n    }\n\n    public enum AdsSize\n    {\n        Banner = 0, // 320x50\n        Adaptive = 5, // full width\n        MediumRectangle = 1, // 300x250\n        IABBanner = 2, // 468x60\n        Leaderboard = 3, // 728x90\n        // SmartBanner = 4,\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdSetting.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4faf330974234e808669c796dc78cdee\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdStatic.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.DataStorage;\n\nnamespace VirtueSky.Ads\n{\n    public static class AdStatic\n    {\n        public static bool IsRemoveAd\n        {\n            get => GameData.Get($\"{Application.identifier}_removeads\", false);\n            set => GameData.Set($\"{Application.identifier}_removeads\", value);\n        }\n\n        public static DateTime AdClosingTime { get; internal set; }\n\n        private static bool isShowingAd;\n\n        public static bool IsShowingAd\n        {\n            get => isShowingAd;\n            internal set\n            {\n                isShowingAd = value;\n                if (!value)\n                {\n                    AdClosingTime = DateTime.Now;\n                }\n            }\n        }\n\n        internal static Action waitAppOpenDisplayedAction;\n        internal static Action waitAppOpenClosedAction;\n\n        public static AdUnitVariable OnDisplayed(this AdUnitVariable unit, Action onDisplayed)\n        {\n            unit.displayedCallback = onDisplayed;\n            return unit;\n        }\n\n        public static AdUnitVariable OnClosed(this AdUnitVariable unit, Action onClosed)\n        {\n            unit.closedCallback = onClosed;\n            return unit;\n        }\n\n        public static AdUnitVariable OnLoaded(this AdUnitVariable unit, Action onLoaded)\n        {\n            unit.loadedCallback = onLoaded;\n            return unit;\n        }\n\n        public static AdUnitVariable OnFailedToLoad(this AdUnitVariable unit, Action onFailedToLoad)\n        {\n            unit.failedToLoadCallback = onFailedToLoad;\n            return unit;\n        }\n\n        public static AdUnitVariable OnFailedToDisplay(this AdUnitVariable unit, Action onFailedToDisplay)\n        {\n            unit.failedToDisplayCallback = onFailedToDisplay;\n            return unit;\n        }\n\n        public static AdUnitVariable OnClicked(this AdUnitVariable unit, Action onClicked)\n        {\n            unit.clickedCallback = onClicked;\n            return unit;\n        }\n\n        public static AdUnitVariable OnCompleted(this AdUnitVariable unit, Action onCompleted)\n        {\n            if (!Application.isMobilePlatform)\n            {\n                onCompleted?.Invoke();\n            }\n\n            switch (unit)\n            {\n                case AdmobInterVariable admobInter:\n                    admobInter.completedCallback = onCompleted;\n                    return unit;\n                case AdmobRewardVariable admobReward:\n                    admobReward.completedCallback = onCompleted;\n                    return unit;\n                case AdmobRewardInterVariable admobRewardInter:\n                    admobRewardInter.completedCallback = onCompleted;\n                    return unit;\n                case MaxInterVariable maxInter:\n                    maxInter.completedCallback = onCompleted;\n                    return unit;\n                case MaxRewardVariable maxReward:\n                    maxReward.completedCallback = onCompleted;\n                    return unit;\n                case LevelPlayInterVariable ironSourceInterVariable:\n                    ironSourceInterVariable.completedCallback = onCompleted;\n                    return unit;\n                case LevelPlayRewardVariable ironSourceRewardVariable:\n                    ironSourceRewardVariable.completedCallback = onCompleted;\n                    return unit;\n            }\n\n            return unit;\n        }\n\n        public static AdUnitVariable OnSkipped(this AdUnitVariable unit, Action onSkipped)\n        {\n            switch (unit)\n            {\n                case AdmobRewardVariable admobReward:\n                    admobReward.skippedCallback = onSkipped;\n                    return unit;\n                case AdmobRewardInterVariable admobRewardInter:\n                    admobRewardInter.skippedCallback = onSkipped;\n                    return unit;\n                case MaxRewardVariable maxReward:\n                    maxReward.skippedCallback = onSkipped;\n                    return unit;\n                case LevelPlayRewardVariable ironSourceRewardVariable:\n                    ironSourceRewardVariable.skippedCallback = onSkipped;\n                    return unit;\n            }\n\n            return unit;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdStatic.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4132cc5be9fa4959a8bafd62a51bb7ca\ntimeCreated: 1695460884"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdUnitVariable.cs",
    "content": "using System;\nusing UnityEngine;\n\n\nnamespace VirtueSky.Ads\n{\n    public abstract class AdUnitVariable : ScriptableObject, IAdUnit\n    {\n        [NonSerialized] internal Action loadedCallback;\n        [NonSerialized] internal Action failedToLoadCallback;\n        [NonSerialized] internal Action displayedCallback;\n        [NonSerialized] internal Action failedToDisplayCallback;\n        [NonSerialized] internal Action closedCallback;\n        [NonSerialized] internal Action clickedCallback;\n        [NonSerialized] public Action<double, string, string, string, string> paidedCallback;\n\n        public Action OnLoadAdEvent;\n        public Action<string> OnFailedToLoadAdEvent;\n        public Action OnDisplayedAdEvent;\n        public Action<string> OnFailedToDisplayAdEvent;\n        public Action OnClosedAdEvent;\n        public Action OnClickedAdEvent;\n\n        public abstract bool IsShowing { get; internal set; }\n        public virtual string Id\n        {\n            get => \"\";\n        }\n\n        protected virtual void ShowImpl(string placement = null)\n        {\n        }\n\n        protected virtual void ResetChainCallback()\n        {\n            loadedCallback = null;\n            failedToDisplayCallback = null;\n            failedToLoadCallback = null;\n            closedCallback = null;\n        }\n\n        public virtual void HideBanner()\n        {\n        }\n\n        public abstract AdUnitVariable Show(string placement = null);\n\n        public virtual void Init()\n        {\n        }\n\n        public virtual void Load()\n        {\n        }\n\n        public virtual bool IsReady()\n        {\n            return false;\n        }\n\n        public virtual void Destroy()\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/AdUnitVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0a0b123368074cd1a359dea0f1ef9233\ntimeCreated: 1695460627"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/Advertising.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\n#if VIRTUESKY_ADMOB\nusing GoogleMobileAds.Api;\nusing GoogleMobileAds.Ump.Api;\n#endif\n\n#if UNITY_IOS\nusing Unity.Advertisement.IosSupport;\n#endif\n\nusing UnityEngine;\nusing UnityEngine.Serialization;\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Ads\n{\n    [EditorIcon(\"icon_controller\"), HideMonoScript]\n    public class Advertising : MonoBehaviour\n    {\n        [Space] [SerializeField] private bool dontDestroyOnLoad = false;\n        [Tooltip(\"Require\"), SerializeField] private AdSetting adSetting;\n\n        [Tooltip(\"Allows nulls\"), SerializeField]\n        private BooleanEvent changePreventDisplayAppOpenEvent;\n\n#if VIRTUESKY_ADMOB\n        [Space] [HeaderLine(\"Admob GDPR\")] [Tooltip(\"Allows nulls\"), SerializeField]\n        private EventNoParam callShowAgainGDPREvent;\n#endif\n\n\n        private IEnumerator autoLoadAdCoroutine;\n        private float _lastTimeLoadInterstitialAdTimestamp = DEFAULT_TIMESTAMP;\n        private float _lastTimeLoadRewardedTimestamp = DEFAULT_TIMESTAMP;\n        private float _lastTimeLoadRewardedInterstitialTimestamp = DEFAULT_TIMESTAMP;\n        private float _lastTimeLoadAppOpenTimestamp = DEFAULT_TIMESTAMP;\n        private const float DEFAULT_TIMESTAMP = -1000;\n\n        // private AdClient currentAdClient;\n        private AdClient maxAdClient;\n        private AdClient admobAdClient;\n        private AdClient ironSourceAdClient;\n\n        private void Awake()\n        {\n            if (dontDestroyOnLoad)\n            {\n                DontDestroyOnLoad(this.gameObject);\n            }\n        }\n\n        private void OnEnable()\n        {\n#if VIRTUESKY_ADMOB\n            if (callShowAgainGDPREvent != null)\n            {\n                callShowAgainGDPREvent.AddListener(ShowPrivacyOptionsForm);\n            }\n#endif\n        }\n\n        private void OnDisable()\n        {\n#if VIRTUESKY_ADMOB\n            if (callShowAgainGDPREvent != null)\n            {\n                callShowAgainGDPREvent.RemoveListener(ShowPrivacyOptionsForm);\n            }\n#endif\n        }\n\n        private void Start()\n        {\n            if (changePreventDisplayAppOpenEvent != null)\n                changePreventDisplayAppOpenEvent.AddListener(OnChangePreventDisplayOpenAd);\n            if (adSetting.EnableGDPR)\n            {\n#if VIRTUESKY_ADMOB\n#if UNITY_IOS\n                if (ATTrackingStatusBinding.GetAuthorizationTrackingStatus() ==\n                    ATTrackingStatusBinding.AuthorizationTrackingStatus.AUTHORIZED)\n                {\n                    InitGdpr();\n                }\n                else\n                {\n                    InitAdClient();\n                }\n#else\n                InitGdpr();\n#endif\n\n\n#endif\n            }\n            else\n            {\n                InitAdClient();\n            }\n        }\n\n        void InitAdClient()\n        {\n            AppTracking.Init(adSetting.EnableTrackAdRevenue);\n            if (adSetting.UseAppLovin)\n            {\n                maxAdClient = new MaxAdClient(adSetting);\n                maxAdClient.Initialize();\n                Debug.Log($\"Use: {maxAdClient}\".SetColor(CustomColor.Cyan));\n            }\n\n            if (adSetting.UseAdmob)\n            {\n                admobAdClient = new AdmobAdClient(adSetting);\n                admobAdClient.Initialize();\n                Debug.Log($\"Use: {admobAdClient}\".SetColor(CustomColor.Cyan));\n            }\n\n            if (adSetting.UseLevelPlay)\n            {\n                ironSourceAdClient = new LevelPlayAdClient(adSetting);\n                ironSourceAdClient.Initialize();\n                Debug.Log($\"Use: {ironSourceAdClient}\".SetColor(CustomColor.Cyan));\n            }\n\n            InitAutoLoadAds();\n        }\n\n        private void InitAutoLoadAds()\n        {\n            if (autoLoadAdCoroutine != null) StopCoroutine(autoLoadAdCoroutine);\n            autoLoadAdCoroutine = IeAutoLoadAll();\n            StartCoroutine(autoLoadAdCoroutine);\n        }\n\n        private void OnChangePreventDisplayOpenAd(bool state)\n        {\n            AdStatic.IsShowingAd = state;\n        }\n\n        IEnumerator IeAutoLoadAll(float delay = 0)\n        {\n            if (delay > 0) yield return new WaitForSeconds(delay);\n            while (true)\n            {\n                AutoLoadInterAds();\n                AutoLoadRewardAds();\n                AutoLoadRewardInterAds();\n                AutoLoadAppOpenAds();\n                yield return new WaitForSeconds(adSetting.AdCheckingInterval);\n            }\n        }\n\n        #region Func Load Ads\n\n        void AutoLoadInterAds()\n        {\n            if (Time.realtimeSinceStartup - _lastTimeLoadInterstitialAdTimestamp <\n                adSetting.AdLoadingInterval) return;\n            if (adSetting.UseAppLovin) maxAdClient.LoadInterstitial();\n            if (adSetting.UseAdmob) admobAdClient.LoadInterstitial();\n            if (adSetting.UseLevelPlay) ironSourceAdClient.LoadInterstitial();\n            _lastTimeLoadInterstitialAdTimestamp = Time.realtimeSinceStartup;\n        }\n\n        void AutoLoadRewardAds()\n        {\n            if (Time.realtimeSinceStartup - _lastTimeLoadRewardedTimestamp <\n                adSetting.AdLoadingInterval) return;\n            if (adSetting.UseAppLovin) maxAdClient.LoadRewarded();\n            if (adSetting.UseAdmob) admobAdClient.LoadRewarded();\n            if (adSetting.UseLevelPlay) ironSourceAdClient.LoadRewarded();\n            _lastTimeLoadRewardedTimestamp = Time.realtimeSinceStartup;\n        }\n\n        void AutoLoadRewardInterAds()\n        {\n            if (Time.realtimeSinceStartup - _lastTimeLoadRewardedInterstitialTimestamp <\n                adSetting.AdLoadingInterval) return;\n            if (adSetting.UseAppLovin) maxAdClient.LoadRewardedInterstitial();\n            if (adSetting.UseAdmob) admobAdClient.LoadRewardedInterstitial();\n            if (adSetting.UseLevelPlay) ironSourceAdClient.LoadRewardedInterstitial();\n            _lastTimeLoadRewardedInterstitialTimestamp = Time.realtimeSinceStartup;\n        }\n\n        void AutoLoadAppOpenAds()\n        {\n            if (Time.realtimeSinceStartup - _lastTimeLoadAppOpenTimestamp <\n                adSetting.AdLoadingInterval) return;\n            if (adSetting.UseAppLovin) maxAdClient.LoadAppOpen();\n            if (adSetting.UseAdmob) admobAdClient.LoadAppOpen();\n            if (adSetting.UseLevelPlay) ironSourceAdClient.LoadAppOpen();\n            _lastTimeLoadAppOpenTimestamp = Time.realtimeSinceStartup;\n        }\n\n        #endregion\n\n        #region Admob GDPR\n\n#if VIRTUESKY_ADMOB\n        private void InitGdpr()\n        {\n#if UNITY_EDITOR\n            InitAdClient();\n#else\n            string deviceID = SystemInfo.deviceUniqueIdentifier;\n            string deviceIDUpperCase = deviceID.ToUpper();\n\n            Debug.Log(\"TestDeviceHashedId = \" + deviceIDUpperCase);\n            ConsentRequestParameters request = new ConsentRequestParameters { TagForUnderAgeOfConsent = false };\n            if (adSetting.EnableGDPRTestMode)\n            {\n                List<string> listDeviceIdTestMode = new List<string>();\n                listDeviceIdTestMode.Add(deviceIDUpperCase);\n                request.ConsentDebugSettings = new ConsentDebugSettings\n                {\n                    DebugGeography = DebugGeography.EEA,\n                    TestDeviceHashedIds = listDeviceIdTestMode\n                };\n            }\n\n            ConsentInformation.Update(request, OnConsentInfoUpdated);\n#endif\n        }\n\n        private void OnConsentInfoUpdated(FormError consentError)\n        {\n            if (consentError != null)\n            {\n                Debug.Log(\"error consentError = \" + consentError);\n                return;\n            }\n\n            ConsentForm.LoadAndShowConsentFormIfRequired((FormError formError) =>\n                {\n                    if (formError != null)\n                    {\n                        Debug.Log(\"error consentError = \" + consentError);\n                        return;\n                    }\n\n                    Debug.Log(\"ConsentStatus = \" + ConsentInformation.ConsentStatus.ToString());\n                    Debug.Log(\"CanRequestAds = \" + ConsentInformation.CanRequestAds());\n\n                    if (ConsentInformation.CanRequestAds())\n                    {\n                        MobileAds.RaiseAdEventsOnUnityMainThread = true;\n                        InitAdClient();\n                    }\n                }\n            );\n        }\n\n        public void LoadAndShowConsentForm()\n        {\n            Debug.Log(\"LoadAndShowConsentForm Start!\");\n\n            ConsentForm.Load((consentForm, loadError) =>\n            {\n                if (loadError != null)\n                {\n                    Debug.Log(\"error loadError = \" + loadError);\n                    return;\n                }\n\n\n                consentForm.Show(showError =>\n                {\n                    if (showError != null)\n                    {\n                        Debug.Log(\"error showError = \" + showError);\n                        return;\n                    }\n                });\n            });\n        }\n\n        private void ShowPrivacyOptionsForm()\n        {\n            Debug.Log(\"Showing privacy options form.\");\n\n            ConsentForm.ShowPrivacyOptionsForm((FormError showError) =>\n            {\n                if (showError != null)\n                {\n                    Debug.LogError(\"Error showing privacy options form with error: \" + showError.Message);\n                }\n            });\n        }\n#endif\n\n        #endregion\n\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            adSetting = CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Ads.AdSetting>(\"/Ads/Setting\");\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/Advertising.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e380b752cb6c40aaace317083692044f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/IAdUnit.cs",
    "content": "namespace VirtueSky.Ads\n{\n    public interface IAdUnit\n    {\n        public void Init();\n        public void Load();\n        public bool IsReady();\n        public void Destroy();\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General/IAdUnit.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5114c7ef942a40ff9e7dbf458d6ed339\ntimeCreated: 1728631990"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/General.meta",
    "content": "fileFormatVersion: 2\nguid: f3d6f74e978547a43947efa49ed48e87\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdClient.cs",
    "content": "#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\nusing Unity.Services.LevelPlay;\n#endif\nusing VirtueSky.Core;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    public sealed class LevelPlayAdClient : AdClient\n    {\n        public LevelPlayAdClient(AdSetting _adSetting)\n        {\n            adSetting = _adSetting;\n        }\n\n        public bool SdkInitializationCompleted { get; private set; }\n\n        public override void Initialize()\n        {\n            SdkInitializationCompleted = false;\n            if (adSetting.UseTestAppKey)\n            {\n                adSetting.AndroidAppKey = \"85460dcd\";\n                adSetting.IosAppKey = \"8545d445\";\n            }\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            App.AddPauseCallback(OnAppStateChange);\n            LevelPlay.OnInitSuccess += SdkInitializationCompletedEvent;\n            LevelPlay.OnImpressionDataReady += ImpressionDataReadyEvent;\n            adSetting.LevelPlayBannerVariable.Init();\n            adSetting.LevelPlayInterVariable.Init();\n            adSetting.LevelPlayRewardVariable.Init();\n            LevelPlay.ValidateIntegration();\n            LevelPlay.Init(adSetting.AppKey);\n#endif\n        }\n\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n        private void ImpressionDataReadyEvent(LevelPlayImpressionData impressionData)\n        {\n            if (impressionData.Revenue != null)\n            {\n                AppTracking.TrackRevenue((double)impressionData.Revenue, impressionData.AdNetwork,\n                    impressionData.MediationAdUnitId,\n                    impressionData.AdFormat, AdMediation.LevelPlay.ToString());\n            }\n        }\n\n        private void OnAppStateChange(bool pauseStatus)\n        {\n            LevelPlay.SetPauseGame(pauseStatus);\n        }\n\n        void SdkInitializationCompletedEvent(LevelPlayConfiguration config)\n        {\n            SdkInitializationCompleted = true;\n            LoadInterstitial();\n            LoadRewarded();\n            LoadBanner();\n        }\n#endif\n\n\n        public override void LoadBanner()\n        {\n            if (adSetting.LevelPlayBannerVariable == null) return;\n            adSetting.LevelPlayBannerVariable.Load();\n        }\n\n        public override void LoadInterstitial()\n        {\n            if (adSetting.LevelPlayInterVariable == null) return;\n            if (!adSetting.LevelPlayInterVariable.IsReady()) adSetting.LevelPlayInterVariable.Load();\n        }\n\n        public override void LoadRewarded()\n        {\n            if (adSetting.LevelPlayRewardVariable == null) return;\n            if (!adSetting.LevelPlayRewardVariable.IsReady()) adSetting.LevelPlayRewardVariable.Load();\n        }\n\n        public override void LoadRewardedInterstitial()\n        {\n        }\n\n        public override void LoadAppOpen()\n        {\n        }\n\n        public override void ShowAppOpen()\n        {\n        }\n\n        public override void LoadNativeOverlay()\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdClient.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 163589e8de4d4fcaaac2df3fbf96f414\ntimeCreated: 1719850536"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdUnitVariable.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Ads\n{\n    public class LevelPlayAdUnitVariable : AdUnitVariable\n    {\n        [SerializeField] protected string androidId;\n        [SerializeField] protected string iOSId;\n        [NonSerialized] private string idRuntime = string.Empty;\n\n        public override bool IsShowing { get; internal set; }\n\n        public override string Id\n        {\n            get\n            {\n                if (idRuntime == String.Empty)\n                {\n#if UNITY_ANDROID\n                    return androidId;\n#elif UNITY_IOS\n                    return iOSId;\n#else\n                    return string.Empty;\n#endif\n                }\n\n                return idRuntime;\n            }\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!Application.isMobilePlatform || AdStatic.IsRemoveAd || !IsReady()) return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        public void SetIdRuntime(string unitId)\n        {\n            idRuntime = unitId;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayAdUnitVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 591b3c010489423bba0d8576ef5fbe49\ntimeCreated: 1728631885"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayBannerVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\nusing Unity.Services.LevelPlay;\nusing VirtueSky.Core;\n#endif\nusing System.Collections;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class LevelPlayBannerVariable : LevelPlayAdUnitVariable\n    {\n        public AdsSize size;\n        public AdsPosition position;\n        public bool isShowOnLoad;\n        private bool _isBannerDestroyed = true;\n        private bool _isBannerShowing;\n        private bool _previousBannerShowStatus;\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n        private LevelPlayBannerAd bannerAd;\n        private readonly WaitForSeconds _waitBannerReload = new WaitForSeconds(5f);\n        private IEnumerator _reload;\n#endif\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            if (AdStatic.IsRemoveAd) return;\n            _isBannerDestroyed = true;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            if (AdStatic.IsRemoveAd) return;\n            Destroy();\n            LevelPlayBannerAd.Config.Builder builder = new LevelPlayBannerAd.Config.Builder();\n            builder.SetPosition(ConvertBannerPosition());\n            builder.SetSize(ConvertBannerSize());\n            builder.SetDisplayOnLoad(isShowOnLoad);\n            var config = builder.Build();\n            bannerAd = new LevelPlayBannerAd(Id, config);\n            bannerAd.OnAdLoaded += BannerOnAdLoadedEvent;\n            bannerAd.OnAdLoadFailed += BannerOnAdLoadFailedEvent;\n            bannerAd.OnAdClicked += BannerOnAdClickedEvent;\n            bannerAd.OnAdDisplayed += BannerOnAdDisplayedEvent;\n            bannerAd.OnAdDisplayFailed += BannerOnAdDisplayFailedEvent;\n            bannerAd.OnAdLeftApplication += BannerOnAdLeftApplicationEvent;\n            bannerAd.LoadAd();\n            _isBannerDestroyed = false;\n#endif\n        }\n\n        void OnWaitAppOpenClosed()\n        {\n            if (_previousBannerShowStatus)\n            {\n                _previousBannerShowStatus = false;\n                Show();\n            }\n        }\n\n        void OnWaitAppOpenDisplayed()\n        {\n            _previousBannerShowStatus = _isBannerShowing;\n            if (_isBannerShowing) HideBanner();\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            return bannerAd != null;\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            _isBannerShowing = true;\n            IsShowing = true;\n            AdStatic.waitAppOpenClosedAction = OnWaitAppOpenClosed;\n            AdStatic.waitAppOpenDisplayedAction = OnWaitAppOpenDisplayed;\n            Load();\n            bannerAd.ShowAd();\n#endif\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            _isBannerShowing = false;\n            _isBannerDestroyed = true;\n            IsShowing = false;\n            AdStatic.waitAppOpenClosedAction = null;\n            AdStatic.waitAppOpenDisplayedAction = null;\n            bannerAd.DestroyAd();\n#endif\n        }\n\n        public override void HideBanner()\n        {\n            base.HideBanner();\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            _isBannerShowing = false;\n            IsShowing = false;\n            bannerAd.HideAd();\n#endif\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n\n        private LevelPlayAdSize ConvertBannerSize()\n        {\n            switch (size)\n            {\n                case AdsSize.Banner: return LevelPlayAdSize.BANNER;\n                case AdsSize.Adaptive: return LevelPlayAdSize.LARGE;\n                case AdsSize.MediumRectangle: return LevelPlayAdSize.MEDIUM_RECTANGLE;\n                case AdsSize.Leaderboard: return LevelPlayAdSize.LEADERBOARD;\n                default: return LevelPlayAdSize.BANNER;\n            }\n        }\n\n        private LevelPlayBannerPosition ConvertBannerPosition()\n        {\n            switch (position)\n            {\n                case AdsPosition.Bottom: return LevelPlayBannerPosition.BottomCenter;\n                case AdsPosition.Top: return LevelPlayBannerPosition.TopCenter;\n                default: return LevelPlayBannerPosition.BottomCenter;\n            }\n        }\n\n        #region Fun Callback\n\n        void BannerOnAdLoadedEvent(LevelPlayAdInfo adInfo)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        void BannerOnAdLoadFailedEvent(LevelPlayAdError ironSourceError)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(ironSourceError.ErrorMessage);\n            if (_reload != null) App.StopCoroutine(_reload);\n            _reload = DelayBannerReload();\n            App.StartCoroutine(_reload);\n        }\n\n        private IEnumerator DelayBannerReload()\n        {\n            yield return _waitBannerReload;\n            Load();\n        }\n\n        void BannerOnAdClickedEvent(LevelPlayAdInfo adInfo)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        void BannerOnAdDisplayedEvent(LevelPlayAdInfo adInfo)\n        {\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        void BannerOnAdDisplayFailedEvent(LevelPlayAdInfo adInfo, LevelPlayAdError adError)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(adError.ErrorMessage);\n        }\n\n        void BannerOnAdLeftApplicationEvent(LevelPlayAdInfo adInfo)\n        {\n        }\n\n        #endregion\n\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayBannerVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f5151f19197e497aa56422344920b819\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayInterVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\nusing Unity.Services.LevelPlay;\n#endif\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class LevelPlayInterVariable : LevelPlayAdUnitVariable\n    {\n        [NonSerialized] internal Action completedCallback;\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n        private LevelPlayInterstitialAd interstitialAd;\n#endif\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            if (AdStatic.IsRemoveAd) return;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            if (AdStatic.IsRemoveAd) return;\n            var configBuilder = new LevelPlayInterstitialAd.Config.Builder();\n            var config = configBuilder.Build();\n            interstitialAd = new LevelPlayInterstitialAd(Id, config);\n            interstitialAd.OnAdLoaded += InterstitialOnAdLoadedEvent;\n            interstitialAd.OnAdLoadFailed += InterstitialOnAdLoadFailed;\n            interstitialAd.OnAdDisplayed += InterstitialOnAdDisplayEvent;\n            interstitialAd.OnAdClicked += InterstitialOnAdClickedEvent;\n            interstitialAd.OnAdDisplayFailed += InterstitialOnAdDisplayFailedEvent;\n            interstitialAd.OnAdClosed += InterstitialOnAdClosedEvent;\n            interstitialAd.LoadAd();\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            return interstitialAd.IsAdReady();\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            interstitialAd.ShowAd(placement);\n#endif\n        }\n\n        public override void Destroy()\n        {\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n\n        #region Fun Callback\n\n        void InterstitialOnAdLoadedEvent(LevelPlayAdInfo adInfo)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        void InterstitialOnAdLoadFailed(LevelPlayAdError ironSourceError)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(ironSourceError.ErrorMessage);\n        }\n\n        void InterstitialOnAdDisplayEvent(LevelPlayAdInfo adInfo)\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        void InterstitialOnAdClickedEvent(LevelPlayAdInfo adInfo)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        void InterstitialOnAdDisplayFailedEvent(LevelPlayAdInfo adInfo, LevelPlayAdError adError)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(adError.ErrorMessage);\n        }\n\n        void InterstitialOnAdClosedEvent(LevelPlayAdInfo adInfo)\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref completedCallback);\n            OnClosedAdEvent?.Invoke();\n            Load();\n        }\n\n        #endregion\n\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayInterVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1c4f30e37f14d78abad68a6b2d0a847\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayRewardVariable.cs",
    "content": "using System;\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\nusing Unity.Services.LevelPlay;\n#endif\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class LevelPlayRewardVariable : LevelPlayAdUnitVariable\n    {\n        [NonSerialized] internal Action completedCallback;\n        [NonSerialized] internal Action skippedCallback;\n        public bool IsEarnRewarded { get; private set; }\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n        LevelPlayRewardedAd rewardedAd;\n#endif\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            if (AdStatic.IsRemoveAd) return;\n#endif\n        }\n\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            if (AdStatic.IsRemoveAd) return;\n            var configBuilder = new LevelPlayRewardedAd.Config.Builder();\n            var config = configBuilder.Build();\n            rewardedAd = new LevelPlayRewardedAd(Id, config);\n            rewardedAd.OnAdLoaded += OnAdLoaded;\n            rewardedAd.OnAdDisplayed += RewardedVideoOnAdDisplayedEvent;\n            rewardedAd.OnAdClosed += RewardedVideoOnAdClosedEvent;\n            rewardedAd.OnAdDisplayFailed += RewardedVideoOnAdDisplayFailedEvent;\n            rewardedAd.OnAdRewarded += RewardedVideoOnAdRewardedEvent;\n            rewardedAd.OnAdClicked += RewardedVideoOnAdClickedEvent;\n            rewardedAd.OnAdLoadFailed += RewardedVideoOnAdLoadFailedEvent;\n            rewardedAd.LoadAd();\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            return rewardedAd != null && rewardedAd.IsAdReady();\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n            rewardedAd.ShowAd(placement);\n#endif\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!UnityEngine.Application.isMobilePlatform || !IsReady()) return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        public override void Destroy()\n        {\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n            skippedCallback = null;\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_LEVELPLAY\n\n        #region Fun Callback\n\n        void OnAdLoaded(LevelPlayAdInfo adInfo)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void RewardedVideoOnAdLoadFailedEvent(LevelPlayAdError ironSourceError)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(ironSourceError.ToString());\n        }\n\n        void RewardedVideoOnAdDisplayedEvent(LevelPlayAdInfo adInfo)\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        void RewardedVideoOnAdClosedEvent(LevelPlayAdInfo adInfo)\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n            if (!IsReady()) rewardedAd.LoadAd();\n            if (IsEarnRewarded)\n            {\n                Common.CallActionAndClean(ref completedCallback);\n                IsEarnRewarded = false;\n                return;\n            }\n\n            Common.CallActionAndClean(ref skippedCallback);\n        }\n\n        void RewardedVideoOnAdDisplayFailedEvent(LevelPlayAdInfo adInfo, LevelPlayAdError ironSourceError)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(ironSourceError.ToString());\n        }\n\n        void RewardedVideoOnAdRewardedEvent(LevelPlayAdInfo info, LevelPlayReward reward)\n        {\n            IsEarnRewarded = true;\n        }\n\n        void RewardedVideoOnAdClickedEvent(LevelPlayAdInfo adInfo)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n        #endregion\n\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable/LevelPlayRewardVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6cb21eb6778e4c0ea10445060b08a271\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay/LevelPlayUnitVariable.meta",
    "content": "fileFormatVersion: 2\nguid: 7d50cc93b33f4995a04161afc0514175\ntimeCreated: 1719850500"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/LevelPlay.meta",
    "content": "fileFormatVersion: 2\nguid: 1170ec045aef4f39ba9d642d37973423\ntimeCreated: 1719850368"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxAdClient.cs",
    "content": "using VirtueSky.Core;\n\nnamespace VirtueSky.Ads\n{\n    public sealed class MaxAdClient : AdClient\n    {\n        public MaxAdClient(AdSetting _adSetting)\n        {\n            adSetting = _adSetting;\n        }\n\n        public override void Initialize()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            MaxSdk.SetSdkKey(adSetting.SdkKey);\n            MaxSdk.InitializeSdk();\n            adSetting.MaxBannerVariable.Init();\n            adSetting.MaxInterVariable.Init();\n            adSetting.MaxRewardVariable.Init();\n            adSetting.MaxAppOpenVariable.Init();\n            App.AddPauseCallback(OnAppStateChange);\n            LoadInterstitial();\n            LoadRewarded();\n            LoadRewardedInterstitial();\n            LoadAppOpen();\n            LoadBanner();\n#endif\n        }\n\n\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n        private void OnAppStateChange(bool pauseStatus)\n        {\n            if (!pauseStatus && adSetting.MaxAppOpenVariable.autoShow)\n            {\n                if (adSetting.UseAppLovin) ShowAppOpen();\n            }\n        }\n#endif\n\n        public override void LoadBanner()\n        {\n            if (adSetting.MaxBannerVariable == null) return;\n            adSetting.MaxBannerVariable.Load();\n        }\n\n        public override void LoadInterstitial()\n        {\n            if (adSetting.MaxInterVariable == null) return;\n            if (!adSetting.MaxInterVariable.IsReady()) adSetting.MaxInterVariable.Load();\n        }\n\n        public override void LoadRewarded()\n        {\n            if (adSetting.MaxRewardVariable == null) return;\n            if (!adSetting.MaxRewardVariable.IsReady()) adSetting.MaxRewardVariable.Load();\n        }\n\n        public override void LoadRewardedInterstitial()\n        {\n        }\n\n        public override void LoadAppOpen()\n        {\n            if (adSetting.MaxAppOpenVariable == null) return;\n            if (!adSetting.MaxAppOpenVariable.IsReady()) adSetting.MaxAppOpenVariable.Load();\n        }\n\n        public override void ShowAppOpen()\n        {\n            if (statusAppOpenFirstIgnore) adSetting.MaxAppOpenVariable.Show();\n            statusAppOpenFirstIgnore = true;\n        }\n\n        public override void LoadNativeOverlay()\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxAdClient.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ccaea541beb11497691c82e48d3e2bf7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxAdUnitVariable.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Ads\n{\n    public class MaxAdUnitVariable : AdUnitVariable\n    {\n        [SerializeField] protected string androidId;\n        [SerializeField] protected string iOSId;\n        [NonSerialized] private string idRuntime = string.Empty;\n\n        public override bool IsShowing { get; internal set; }\n\n        public override string Id\n        {\n            get\n            {\n                if (idRuntime == String.Empty)\n                {\n#if UNITY_ANDROID\n                    return androidId;\n#elif UNITY_IOS\n                    return iOSId;\n#else\n                    return string.Empty;\n#endif\n                }\n\n                return idRuntime;\n            }\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!Application.isMobilePlatform || string.IsNullOrEmpty(Id) || AdStatic.IsRemoveAd ||\n                !IsReady()) return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        public void SetIdRuntime(string unitId)\n        {\n            idRuntime = unitId;\n        }\n\n        \n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxAdUnitVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8d49a7d460324b64bf0e810452eb8db6\ntimeCreated: 1728632190"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxAppOpenVariable.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class MaxAppOpenVariable : MaxAdUnitVariable\n    {\n        [Tooltip(\"Automatically show AppOpenAd when app status is changed\")]\n        public bool autoShow = false;\n\n        [Tooltip(\"Time between closing the previous full-screen ad and starting to show the app open ad - in seconds\")]\n        public float timeBetweenFullScreenAd = 2f;\n\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n            MaxSdkCallbacks.AppOpen.OnAdDisplayedEvent += OnAdDisplayed;\n            MaxSdkCallbacks.AppOpen.OnAdHiddenEvent += OnAdHidden;\n            MaxSdkCallbacks.AppOpen.OnAdLoadedEvent += OnAdLoaded;\n            MaxSdkCallbacks.AppOpen.OnAdDisplayFailedEvent += OnAdDisplayFailed;\n            MaxSdkCallbacks.AppOpen.OnAdLoadFailedEvent += OnAdLoadFailed;\n            MaxSdkCallbacks.AppOpen.OnAdRevenuePaidEvent += OnAdRevenuePaid;\n            MaxSdkCallbacks.AppOpen.OnAdClickedEvent += OnAdClicked;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            MaxSdk.LoadAppOpenAd(Id);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            return !string.IsNullOrEmpty(Id) && MaxSdk.IsAppOpenAdReady(Id) &&\n                   (DateTime.Now - AdStatic.AdClosingTime).TotalSeconds > timeBetweenFullScreenAd;\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            MaxSdk.ShowAppOpenAd(Id, placement: placement);\n#endif\n        }\n\n        public override void Destroy()\n        {\n        }\n\n        #region Func Callback\n\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n        private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info)\n        {\n            paidedCallback?.Invoke(info.Revenue,\n                info.NetworkName,\n                unit,\n                info.AdFormat, AdMediation.AppLovin.ToString());\n        }\n\n        private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(info.Message);\n        }\n\n        private void OnAdDisplayFailed(string unit, MaxSdkBase.ErrorInfo errorInfo,\n            MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(errorInfo.Message);\n        }\n\n        private void OnAdHidden(string unit, MaxSdkBase.AdInfo info)\n        {\n            AdStatic.waitAppOpenClosedAction?.Invoke();\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n            if (!string.IsNullOrEmpty(Id)) MaxSdk.LoadAppOpenAd(Id);\n        }\n\n        private void OnAdDisplayed(string unit, MaxSdkBase.AdInfo info)\n        {\n            AdStatic.waitAppOpenDisplayedAction?.Invoke();\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdClicked(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n#endif\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxAppOpenVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1e29fec6165f4c3baceac878abc88638\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxBannerVariable.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class MaxBannerVariable : MaxAdUnitVariable\n    {\n        public AdsSize size;\n        public AdsPosition position;\n\n        private bool _isBannerDestroyed = true;\n        private bool _isBannerShowing;\n        private bool _previousBannerShowStatus;\n\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n            MaxSdkCallbacks.Banner.OnAdLoadedEvent += OnAdLoaded;\n            MaxSdkCallbacks.Banner.OnAdExpandedEvent += OnAdExpanded;\n            MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += OnAdLoadFailed;\n            MaxSdkCallbacks.Banner.OnAdCollapsedEvent += OnAdCollapsed;\n            MaxSdkCallbacks.Banner.OnAdRevenuePaidEvent += OnAdRevenuePaid;\n            MaxSdkCallbacks.Banner.OnAdClickedEvent += OnAdClicked;\n            if (size != AdsSize.Adaptive)\n            {\n                MaxSdk.SetBannerExtraParameter(Id, \"adaptive_banner\", \"false\");\n            }\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            if (_isBannerDestroyed)\n            {\n                MaxSdk.CreateBanner(Id, ConvertPosition());\n                _isBannerDestroyed = false;\n            }\n#endif\n        }\n\n        void OnWaitAppOpenClosed()\n        {\n            if (_previousBannerShowStatus)\n            {\n                _previousBannerShowStatus = false;\n                Show();\n            }\n        }\n\n        void OnWaitAppOpenDisplayed()\n        {\n            _previousBannerShowStatus = _isBannerShowing;\n            if (_isBannerShowing) HideBanner();\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            return !string.IsNullOrEmpty(Id);\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            _isBannerShowing = true;\n            IsShowing = true;\n            AdStatic.waitAppOpenClosedAction = OnWaitAppOpenClosed;\n            AdStatic.waitAppOpenDisplayedAction = OnWaitAppOpenDisplayed;\n            Load();\n            MaxSdk.ShowBanner(Id);\n#endif\n        }\n\n        public override void Destroy()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (string.IsNullOrEmpty(Id)) return;\n            _isBannerShowing = false;\n            _isBannerDestroyed = true;\n            IsShowing = false;\n            AdStatic.waitAppOpenClosedAction = null;\n            AdStatic.waitAppOpenDisplayedAction = null;\n            MaxSdk.DestroyBanner(Id);\n#endif\n        }\n\n        public override void HideBanner()\n        {\n            base.HideBanner();\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            _isBannerShowing = false;\n            IsShowing = false;\n            if (string.IsNullOrEmpty(Id)) return;\n            MaxSdk.HideBanner(Id);\n#endif\n        }\n\n        #region Fun Callback\n\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n        public MaxSdkBase.BannerPosition ConvertPosition()\n        {\n            switch (position)\n            {\n                case AdsPosition.Top: return MaxSdkBase.BannerPosition.TopCenter;\n                case AdsPosition.Bottom: return MaxSdkBase.BannerPosition.BottomCenter;\n                case AdsPosition.TopLeft: return MaxSdkBase.BannerPosition.TopLeft;\n                case AdsPosition.TopRight: return MaxSdkBase.BannerPosition.TopRight;\n                case AdsPosition.BottomLeft: return MaxSdkBase.BannerPosition.BottomLeft;\n                case AdsPosition.BottomRight: return MaxSdkBase.BannerPosition.BottomRight;\n                default:\n                    return MaxSdkBase.BannerPosition.BottomCenter;\n            }\n        }\n\n        private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info)\n        {\n            paidedCallback?.Invoke(info.Revenue,\n                info.NetworkName,\n                unit,\n                info.AdFormat, AdMediation.AppLovin.ToString());\n        }\n\n        private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdExpanded(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(info.Message);\n            Destroy();\n        }\n\n        private void OnAdCollapsed(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n        }\n\n        private void OnAdClicked(string arg1, MaxSdkBase.AdInfo arg2)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n\n#endif\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxBannerVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2d54005e18d14434a4feed9988bfd43c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxInterVariable.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Ads;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class MaxInterVariable : MaxAdUnitVariable\n    {\n        [NonSerialized] internal Action completedCallback;\n\n\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n            MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnAdLoaded;\n            MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnAdLoadFailed;\n            MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaid;\n            MaxSdkCallbacks.Interstitial.OnAdDisplayedEvent += OnAdDisplayed;\n            MaxSdkCallbacks.Interstitial.OnAdHiddenEvent += OnAdHidden;\n            MaxSdkCallbacks.Interstitial.OnAdDisplayFailedEvent += OnAdDisplayFailed;\n            MaxSdkCallbacks.Interstitial.OnAdClickedEvent += OnAdClicked;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (AdStatic.IsRemoveAd || string.IsNullOrEmpty(Id)) return;\n            MaxSdk.LoadInterstitial(Id);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            return !string.IsNullOrEmpty(Id) && MaxSdk.IsInterstitialReady(Id);\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            MaxSdk.ShowInterstitial(Id, placement: placement);\n#endif\n        }\n\n        public override void Destroy()\n        {\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n        }\n\n        #region Func Callback\n\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n        private void OnAdDisplayFailed(string unit, MaxSdkBase.ErrorInfo error,\n            MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(error.Message);\n        }\n\n        private void OnAdHidden(string unit, MaxSdkBase.AdInfo info)\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref completedCallback);\n            OnClosedAdEvent?.Invoke();\n            if (!string.IsNullOrEmpty(Id)) MaxSdk.LoadInterstitial(Id);\n        }\n\n        private void OnAdDisplayed(string unit, MaxSdkBase.AdInfo info)\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info)\n        {\n            paidedCallback?.Invoke(info.Revenue,\n                info.NetworkName,\n                unit,\n                info.AdFormat, AdMediation.AppLovin.ToString());\n        }\n\n        private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(info.Message);\n        }\n\n        private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdClicked(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n#endif\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxInterVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7f2517077a9341d38d7486727d83a132\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxRewardVariable.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Tracking;\n\nnamespace VirtueSky.Ads\n{\n    [Serializable]\n    [EditorIcon(\"icon_scriptable\")]\n    public class MaxRewardVariable : MaxAdUnitVariable\n    {\n        [NonSerialized] internal Action completedCallback;\n        [NonSerialized] internal Action skippedCallback;\n        public bool IsEarnRewarded { get; private set; }\n\n        public override void Init()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (string.IsNullOrEmpty(Id)) return;\n            paidedCallback += AppTracking.TrackRevenue;\n            MaxSdkCallbacks.Rewarded.OnAdDisplayedEvent += OnAdDisplayed;\n            MaxSdkCallbacks.Rewarded.OnAdHiddenEvent += OnAdHidden;\n            MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnAdLoaded;\n            MaxSdkCallbacks.Rewarded.OnAdDisplayFailedEvent += OnAdDisplayFailed;\n            MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnAdLoadFailed;\n            MaxSdkCallbacks.Rewarded.OnAdRevenuePaidEvent += OnAdRevenuePaid;\n            MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnAdReceivedReward;\n            MaxSdkCallbacks.Rewarded.OnAdClickedEvent += OnAdClicked;\n#endif\n        }\n\n        public override void Load()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            if (string.IsNullOrEmpty(Id)) return;\n            MaxSdk.LoadRewardedAd(Id);\n#endif\n        }\n\n        public override bool IsReady()\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            return !string.IsNullOrEmpty(Id) && MaxSdk.IsRewardedAdReady(Id);\n#else\n            return false;\n#endif\n        }\n\n        protected override void ShowImpl(string placement = null)\n        {\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n            MaxSdk.ShowRewardedAd(Id, placement: placement);\n#endif\n        }\n\n        public override AdUnitVariable Show(string placement = null)\n        {\n            ResetChainCallback();\n            if (!UnityEngine.Application.isMobilePlatform || !IsReady()) return this;\n            ShowImpl(placement);\n            return this;\n        }\n\n        public override void Destroy()\n        {\n        }\n\n        protected override void ResetChainCallback()\n        {\n            base.ResetChainCallback();\n            completedCallback = null;\n            skippedCallback = null;\n        }\n\n        #region Func Callback\n\n#if VIRTUESKY_ADS && VIRTUESKY_APPLOVIN\n        private void OnAdReceivedReward(string unit, MaxSdkBase.Reward reward,\n            MaxSdkBase.AdInfo info)\n        {\n            IsEarnRewarded = true;\n        }\n\n        private void OnAdRevenuePaid(string unit, MaxSdkBase.AdInfo info)\n        {\n            paidedCallback?.Invoke(info.Revenue,\n                info.NetworkName,\n                unit,\n                info.AdFormat, AdMediation.AppLovin.ToString());\n        }\n\n        private void OnAdLoadFailed(string unit, MaxSdkBase.ErrorInfo info)\n        {\n            Common.CallActionAndClean(ref failedToLoadCallback);\n            OnFailedToLoadAdEvent?.Invoke(info.Message);\n        }\n\n        private void OnAdDisplayFailed(string unit, MaxSdkBase.ErrorInfo errorInfo,\n            MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref failedToDisplayCallback);\n            OnFailedToDisplayAdEvent?.Invoke(errorInfo.Message);\n        }\n\n        private void OnAdLoaded(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref loadedCallback);\n            OnLoadAdEvent?.Invoke();\n        }\n\n        private void OnAdHidden(string unit, MaxSdkBase.AdInfo info)\n        {\n            AdStatic.IsShowingAd = false;\n            IsShowing = false;\n            Common.CallActionAndClean(ref closedCallback);\n            OnClosedAdEvent?.Invoke();\n            if (!IsReady()) MaxSdk.LoadRewardedAd(Id);\n            if (IsEarnRewarded)\n            {\n                Common.CallActionAndClean(ref completedCallback);\n                IsEarnRewarded = false;\n                return;\n            }\n\n            Common.CallActionAndClean(ref skippedCallback);\n        }\n\n        private void OnAdDisplayed(string unit, MaxSdkBase.AdInfo info)\n        {\n            AdStatic.IsShowingAd = true;\n            IsShowing = true;\n            Common.CallActionAndClean(ref displayedCallback);\n            OnDisplayedAdEvent?.Invoke();\n        }\n\n        private void OnAdClicked(string unit, MaxSdkBase.AdInfo info)\n        {\n            Common.CallActionAndClean(ref clickedCallback);\n            OnClickedAdEvent?.Invoke();\n        }\n#endif\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable/MaxRewardVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 20d8d1652da34664a50db28dbc997814\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max/MaxUnitVariable.meta",
    "content": "fileFormatVersion: 2\nguid: 74b6a60977c643ee956805295399665c\ntimeCreated: 1695462087"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Max.meta",
    "content": "fileFormatVersion: 2\nguid: f30fd55eb75a48b4691e1a17d8ad50c2\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Virtuesky.Sunflower.Advertising.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Advertising\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:32dbaa332e571bf429b7de517f75f074\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:a4cfc1a18fa3a469b96d885db522f42e\",\n        \"GUID:35d694408290717499b3838802212c7f\",\n        \"GUID:5e9107a8f2499184ea26564811dda246\",\n        \"GUID:760a4c7888534400e882b82c5b3fba06\",\n        \"GUID:00c479e63b1c74419820a39073267645\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Advertising/Runtime/Virtuesky.Sunflower.Advertising.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: abd57f653a468a04c8d4e281527ff293\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: f71c7d92eeff8c34492800ba35756ee8\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Advertising.meta",
    "content": "fileFormatVersion: 2\nguid: 4a6fce59e6956244e8e4045dcfa6387c\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public enum Dependency\n    {\n        All,\n        Direct,\n        Indirect\n    }\n\n    public enum DepthFilter\n    {\n        All,\n        Equal,\n        NotEqual,\n        Less,\n        LessEqual,\n        Greater,\n        GreaterEqual\n    }\n\n    public enum Sorting\n    {\n        None,\n        Type,\n        Path,\n        Size\n    }\n\n    [Serializable]\n    public class AssetFinderInfo\n    {\n        public string guid;\n        public string assetPath;\n        public string fileName;\n        public string extension;\n        public System.Type assetType;\n        public int usageCount;\n        public int usedByCount;\n        public bool isInBuild;\n        public long fileSize;\n        public bool isFolder;\n        public bool isBuiltin;\n\n        public AssetFinderInfo(string guid)\n        {\n            this.guid = guid;\n            RefreshInfo();\n        }\n\n        internal void RefreshInfo()\n        {\n            if (string.IsNullOrEmpty(guid)) return;\n\n            assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(assetPath))\n            {\n                fileName = \"Missing\";\n                extension = \"\";\n                assetType = null;\n                fileSize = 0;\n                isFolder = false;\n                isBuiltin = false;\n                return;\n            }\n\n            fileName = Path.GetFileName(assetPath);\n            extension = Path.GetExtension(assetPath);\n            \n            // Check if it's a folder\n            isFolder = AssetDatabase.IsValidFolder(assetPath);\n            \n            // Check if it's builtin using the proper constant\n            isBuiltin = AssetFinderAsset.BUILT_IN_ASSETS.Contains(guid);\n\n            if (!isFolder)\n            {\n                UnityObject obj = AssetDatabase.LoadAssetAtPath<UnityObject>(assetPath);\n                assetType = obj?.GetType();\n\n                // Get file size\n                try\n                {\n                    if (File.Exists(assetPath))\n                    {\n                        var fileInfo = new FileInfo(assetPath);\n                        fileSize = fileInfo.Length;\n                    }\n                }\n                catch\n                {\n                    fileSize = 0;\n                }\n            }\n            else\n            {\n                assetType = typeof(DefaultAsset);\n                fileSize = 0;\n            }\n\n            // Get usage counts from AssetFinderAsset if available\n            if (AssetFinderCache.isReady)\n            {\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                if (asset != null)\n                {\n                    usageCount = asset.UseGUIDsCount;\n                    usedByCount = asset.UsedByMap.Count;\n                }\n            }\n        }\n\n        internal void UpdateBuildStatus(HashSet<string> buildGuids)\n        {\n            isInBuild = buildGuids != null && buildGuids.Contains(guid);\n        }\n    }\n\n    public static class AssetFinder\n    {\n        public static bool IsReady => AssetFinderCache.isReady;\n\n        public static void ScanProject()\n        {\n            AssetFinderCache.DeleteCache();\n            AssetFinderCache.CreateCache();\n        }\n\n        public static void Refresh()\n        {\n            if (!AssetFinderCache.hasCache)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not found. Use AssetFinder.ScanProject() first.\");\n                return;\n            }\n\n            AssetFinderCache.Api.Check4Changes(true);\n        }\n\n        public static List<AssetFinderInfo> GetUses(string[] guids, Dependency dep = Dependency.All, int depth = 0, DepthFilter filter = DepthFilter.All, Sorting sort = Sorting.None)\n        {\n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return new List<AssetFinderInfo>();\n            }\n\n            if (guids == null || guids.Length == 0) return new List<AssetFinderInfo>();\n\n            Dictionary<string, AssetFinderRef> refs = AssetFinderRef.FindUsage(guids);\n            return ProcessResults(refs, dep, depth, filter, sort);\n        }\n\n        public static List<AssetFinderInfo> GetUsedBy(string[] guids, Dependency dep = Dependency.All, int depth = 0, DepthFilter filter = DepthFilter.All, Sorting sort = Sorting.None)\n        {\n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return new List<AssetFinderInfo>();\n            }\n\n            if (guids == null || guids.Length == 0) return new List<AssetFinderInfo>();\n\n            Dictionary<string, AssetFinderRef> refs = AssetFinderRef.FindUsedBy(guids);\n            return ProcessResults(refs, dep, depth, filter, sort);\n        }\n\n        public static List<AssetFinderInfo> GetUnused(Sorting sort = Sorting.None)\n        {\n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return new List<AssetFinderInfo>();\n            }\n\n            List<AssetFinderAsset> unusedAssets = AssetFinderCache.Api.ScanUnused(true);\n            return ProcessAssetResults(unusedAssets, sort);\n        }\n\n        public static List<AssetFinderInfo> GetInBuild(Sorting sort = Sorting.None)\n        {\n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return new List<AssetFinderInfo>();\n            }\n\n            var usedInBuild = new AssetFinderUsedInBuild(null, () => ConvertSorting(sort), () => AssetFinderRefDrawer.Mode.Type);\n            usedInBuild.RefreshView();\n\n            if (usedInBuild.refs == null) return new List<AssetFinderInfo>();\n\n            var buildGuids = new HashSet<string>(usedInBuild.refs.Keys);\n            var assets = usedInBuild.refs.Values.Select(r => r.asset).ToList();\n            var results = ProcessAssetResults(assets, sort);\n            \n            // Set isInBuild flag for all returned assets\n            foreach (var assetInfo in results)\n            {\n                assetInfo.UpdateBuildStatus(buildGuids);\n            }\n            \n            return results;\n        }\n\n        public static Dictionary<string, int> GetUsesCount(string[] guids)\n        {\n            var result = new Dictionary<string, int>();\n            \n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return result;\n            }\n\n            if (guids == null || guids.Length == 0) return result;\n\n            foreach (string guid in guids)\n            {\n                if (string.IsNullOrEmpty(guid)) continue;\n                \n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                result[guid] = asset?.UseGUIDsCount ?? 0;\n            }\n\n            return result;\n        }\n\n        public static Dictionary<string, int> GetUsedByCount(string[] guids)\n        {\n            var result = new Dictionary<string, int>();\n            \n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return result;\n            }\n\n            if (guids == null || guids.Length == 0) return result;\n\n            foreach (string guid in guids)\n            {\n                if (string.IsNullOrEmpty(guid)) continue;\n                \n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                result[guid] = asset?.UsedByMap.Count ?? 0;\n            }\n\n            return result;\n        }\n\n        public static bool IsUses(string[] guids)\n        {\n            if (!IsReady || guids == null || guids.Length == 0) return false;\n\n            foreach (string guid in guids)\n            {\n                if (string.IsNullOrEmpty(guid)) continue;\n                \n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                if (asset != null && asset.UseGUIDsCount > 0) return true;\n            }\n\n            return false;\n        }\n\n        public static bool IsUsedBy(string[] guids)\n        {\n            if (!IsReady || guids == null || guids.Length == 0) return false;\n\n            foreach (string guid in guids)\n            {\n                if (string.IsNullOrEmpty(guid)) continue;\n                \n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                if (asset != null && asset.UsedByMap.Count > 0) return true;\n            }\n\n            return false;\n        }\n\n        public static bool IsInBuild(string[] guids)\n        {\n            if (!IsReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not ready. Use AssetFinder.ScanProject() first.\");\n                return false;\n            }\n\n            if (guids == null || guids.Length == 0) return false;\n\n            var usedInBuild = new AssetFinderUsedInBuild(null, () => AssetFinderRefDrawer.Sort.Type, () => AssetFinderRefDrawer.Mode.Type);\n            usedInBuild.RefreshView();\n\n            if (usedInBuild.refs == null) return false;\n\n            var buildGuids = new HashSet<string>(usedInBuild.refs.Keys);\n\n            foreach (string guid in guids)\n            {\n                if (buildGuids.Contains(guid)) return true;\n            }\n\n            return false;\n        }\n\n\n\n        private static List<AssetFinderInfo> ProcessAssetResults(List<AssetFinderAsset> assets, Sorting sorting)\n        {\n            if (assets == null) return new List<AssetFinderInfo>();\n\n            var results = new List<AssetFinderInfo>();\n\n            foreach (AssetFinderAsset asset in assets)\n            {\n                if (asset == null) continue;\n                \n                var assetInfo = new AssetFinderInfo(asset.guid);\n                results.Add(assetInfo);\n            }\n\n            return ApplySorting(results, sorting);\n        }\n\n        private static List<AssetFinderInfo> ProcessResults(Dictionary<string, AssetFinderRef> refs, Dependency dependency, int depth, DepthFilter filter, Sorting sorting)\n        {\n            if (refs == null) return new List<AssetFinderInfo>();\n\n            var results = new List<AssetFinderInfo>();\n            var processedGuids = new HashSet<string>();\n\n            foreach (KeyValuePair<string, AssetFinderRef> kvp in refs)\n            {\n                AssetFinderRef refItem = kvp.Value;\n                \n                // Apply dependency filter\n                if (dependency == Dependency.Direct && refItem.depth > 1) continue;\n                if (dependency == Dependency.Indirect && refItem.depth <= 1) continue;\n                \n                // Apply depth filter with mathematically correct comparisons\n                if (!MatchesDepthFilter(refItem.depth, depth, filter)) continue;\n\n                if (processedGuids.Contains(refItem.asset.guid)) continue;\n                processedGuids.Add(refItem.asset.guid);\n\n                var assetInfo = new AssetFinderInfo(refItem.asset.guid);\n                results.Add(assetInfo);\n            }\n\n            return ApplySorting(results, sorting);\n        }\n\n\n\n        private static bool MatchesDepthFilter(int itemDepth, int targetDepth, DepthFilter filter)\n        {\n            switch (filter)\n            {\n                case DepthFilter.All:\n                    return true;\n                case DepthFilter.Equal:\n                    return itemDepth == targetDepth;\n                case DepthFilter.NotEqual:\n                    return itemDepth != targetDepth;\n                case DepthFilter.Less:\n                    return itemDepth < targetDepth;\n                case DepthFilter.LessEqual:\n                    return itemDepth <= targetDepth;\n                case DepthFilter.Greater:\n                    return itemDepth > targetDepth;\n                case DepthFilter.GreaterEqual:\n                    return itemDepth >= targetDepth;\n                default:\n                    return true;\n            }\n        }\n\n\n\n        private static List<AssetFinderInfo> ApplySorting(List<AssetFinderInfo> assetInfos, Sorting sorting)\n        {\n            switch (sorting)\n            {\n                case Sorting.Type:\n                    return assetInfos.OrderBy(info => info.assetType?.Name ?? \"\")\n                                    .ThenBy(info => info.assetPath)\n                                    .ToList();\n                \n                case Sorting.Path:\n                    return assetInfos.OrderBy(info => info.assetPath)\n                                    .ThenBy(info => info.assetType?.Name ?? \"\")\n                                    .ToList();\n                \n                case Sorting.Size:\n                    return assetInfos.OrderByDescending(info => info.fileSize)\n                                    .ThenBy(info => info.assetPath)\n                                    .ToList();\n                \n                default:\n                    return assetInfos;\n            }\n        }\n\n        private static AssetFinderRefDrawer.Sort ConvertSorting(Sorting sorting)\n        {\n            switch (sorting)\n            {\n                case Sorting.Type: return AssetFinderRefDrawer.Sort.Type;\n                case Sorting.Path: return AssetFinderRefDrawer.Sort.Path;\n                case Sorting.Size: return AssetFinderRefDrawer.Sort.Size;\n                default: return AssetFinderRefDrawer.Sort.Type;\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinder.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 336a181c1abdb455f8388370e58f0496\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderAssetType.cs",
    "content": "﻿// deleted"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderAssetType.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b077597d32a3b4e43bd7bfc007c3e6dc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderCacheEditor.cs",
    "content": "﻿// deleted"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderCacheEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 18708e9bf7db0f04fa917a0db924382c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderDuplicate.cs",
    "content": "﻿// deleted"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderDuplicate.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 57aae5701da3c644c937c59e2da6da85\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderRef.cs",
    "content": "﻿// deleted"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderRef.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ef09719313b4f943a49eb3a2b0f934d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderWindowExtension.cs",
    "content": "﻿namespace VirtueSky.AssetFinder.Editor {\n    public class AssetFinderWindowExtension {\n        public static void ShowWindow() {\n            AssetFinderWindowAll.ShowWindow();\n        }\n        public static void DeleteCache() {\n            AssetFinderCache.DeleteCache();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/AssetFinderWindowExtension.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 10b0c9ac533b455baa0c863c779748bd\ntimeCreated: 1764820294"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetState.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    partial class AssetFinderAsset\n    {\n        public enum AssetState\n        {\n            NEW,\n            CACHE,\n            MISSING\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetState.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cd01dcf20ca0ec442af562e1bb400560\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetType.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    partial class AssetFinderAsset\n    {\n        public enum AssetType\n        {\n            UNKNOWN,\n            FOLDER,\n            SCRIPT,\n            SCENE,\n            DLL,\n            REFERENCABLE,\n            BINARY_ASSET,\n            MODEL,\n            TERRAIN,\n            LIGHTING_DATA,\n            NON_READABLE,\n            BUILT_IN\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.AssetType.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0d8fbadc1183faf4fa0008a3c8ef122e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Classes.cs",
    "content": "using System;\nusing System.Collections.Generic;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        [Serializable]\n        internal class Classes\n        {\n            public string guid;\n            public List<long> ids;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Classes.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5474ab83390e2904b92f5b45bd2fe0dc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Constants.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        // ------------------------------ CONSTANTS ---------------------------\n\n        public const int MIN_FILE_SIZE_2LOG = 1024 * 1024; // 1 MB\n        internal static bool shouldWriteImportLog;\n\n        private static readonly HashSet<string> SCRIPT_EXTENSIONS = new HashSet<string>\n        {\n            \".cs\", \".js\", \".boo\", \".h\", \".java\", \".cpp\", \".m\", \".mm\", \".cginclude\", \".shadersubgraph\"\n        };\n\n        private static readonly HashSet<string> REFERENCABLE_EXTENSIONS = new HashSet<string>\n        {\n            \".anim\", \".controller\", \".mat\", \".unity\", \".guiskin\", \".prefab\",\n            \".overridecontroller\", \".mask\", \".rendertexture\", \".cubemap\", \".flare\", \".playable\",\n            \".mat\", \".physicsmaterial\", \".fontsettings\", \".asset\", \".prefs\", \".spriteatlas\",\n            \".terrainlayer\", \".asmdef\", \".preset\", \".spriteLib\", \".shader\", \".hlsl\", \".cginc\", \".glsl\"\n        };\n\n        private static readonly HashSet<string> REFERENCABLE_JSON = new HashSet<string>\n        {\n            \".shadergraph\", \".shadersubgraph\"\n        };\n\n        private static readonly HashSet<string> UI_TOOLKIT = new HashSet<string>\n        {\n            \".uss\", \".uxml\", \".tss\"\n        };\n\n        private static readonly HashSet<string> REFERENCABLE_META = new HashSet<string>\n        {\n            \".texture2darray\",\n            \".png\", \".jpg\", \".jpeg\", \".tga\", \".tif\", \".tiff\", \".psd\", \".bmp\", \".exr\", \".gif\",\n        };\n\n        /// <summary>\n        ///     Extensions that rarely contain references to other assets and can be\n        ///     ignored when deciding if an asset is \"critical\".\n        /// </summary>\n        private static readonly HashSet<string> NON_REFERENCE_EXTENSIONS =\n            new HashSet<string>(StringComparer.OrdinalIgnoreCase)\n            {\n                \".wav\", \".mp3\", \".ogg\", \".aif\", \".aiff\",\n                \".txt\", \".json\", \".xml\", \".csv\",\n                \".html\", \".htm\", \".yaml\", \".md\"\n            };\n\n        internal static readonly HashSet<string> BUILT_IN_ASSETS = new HashSet<string>\n        {\n            \"0000000000000000f000000000000000\",\n            \"0000000000000000e000000000000000\",\n            \"0000000000000000d000000000000000\"\n        };\n\n        private static readonly Dictionary<long, Type> HashClasses = new Dictionary<long, Type>();\n        internal static Dictionary<string, GUIContent> cacheImage = new Dictionary<string, GUIContent>();\n\n        public static float ignoreTS;\n        private static string _logPath;\n        private static int binaryLoaded;\n        private static DateTime scanStartTime;\n\n        private static string logPath\n        {\n            get\n            {\n                if (!string.IsNullOrEmpty(_logPath)) return _logPath;\n                _logPath = System.IO.Path.Combine(Application.dataPath, \"../fr2-import.log\");\n                return _logPath;\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Constants.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9e3eb5ee34a8a3a41b281a3f9d1652e8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.ContentLoader.cs",
    "content": "using System;\nusing System.IO;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        // ----------------------------- CONTENT LOADING ---------------------------------------\n\n        internal void LoadContent()\n        {\n            if (!fileContentDirty) return;\n            m_cachefileWriteTS = m_fileWriteTS;\n            m_forceIncludeInBuild = false;\n\n            if (IsMissing || type == AssetType.NON_READABLE) return;\n            if (type == AssetType.DLL)\n            {\n                AssetFinderLOG.LogWarning(\"Parsing DLL not yet supportted \");\n                return;\n            }\n            \n            AssetFinderLOG.Log(\"LoadContent ... infoHash=\" + fileInfoHash + \": assetPath=\" + m_assetPath);\n\n            var startTime = DateTime.Now;\n            if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG))\n            {\n                var logMessage = $\"{startTime:yyyy-MM-dd HH:mm:ss} - {assetPath}, Size: {fileSize} bytes\";\n                File.AppendAllText(logPath, logMessage + Environment.NewLine);\n            }\n            \n            if (!ExistOnDisk())\n            {\n                state = AssetState.MISSING;\n                return;\n            }\n\n            ClearUseGUIDs();\n\n            if (IsFolder)\n            {\n                LoadFolder();\n            } else if (IsReferencable)\n            {\n                LoadYAML2();\n            } else if (IsBinaryAsset)\n            {\n                LoadBinaryAsset();\n            }\n\n            if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG))\n            {\n                DateTime endTime = DateTime.Now;\n                double duration = (endTime - startTime).TotalMilliseconds;\n                var logMessage = $\", Duration: {duration} ms\";\n                File.AppendAllText(logPath, logMessage + Environment.NewLine);\n            }\n        }\n\n        internal void LoadContentFast()\n        {\n            if (!fileContentDirty) return;\n            m_cachefileWriteTS = m_fileWriteTS;\n            m_forceIncludeInBuild = false;\n\n            if (IsMissing) return;\n            if (type == AssetType.SCRIPT || type == AssetType.DLL || type == AssetType.FOLDER) return;\n            // if (assetPath.StartsWith(\"Packages/\")) return;\n\n            DateTime startTime = DateTime.Now;\n            if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG))\n            {\n                var logMessage = $\"{startTime:yyyy-MM-dd HH:mm:ss} - {assetPath}, Size: {fileSize} bytes\";\n                File.AppendAllText(logPath, logMessage);\n            }\n\n            ClearUseGUIDs();\n\n            if (fileSize > 5 * 1024 * 1024 || type == AssetType.NON_READABLE || IsBinaryAsset)\n            {\n                string[] dependencies = AssetDatabase.GetDependencies(assetPath, false);\n                foreach (string dependency in dependencies)\n                {\n                    string guid = AssetDatabase.AssetPathToGUID(dependency);\n                    if (!string.IsNullOrEmpty(guid) && (guid != this.guid))\n                    {\n                        AddUseGUID(guid);\n                    }\n                }\n            } else if (IsReferencable)\n            {\n                LoadYAML2();\n            }\n            \n            // CRITICAL FIX: Validate with AssetDatabase to catch missing references\n            using (AssetFinderDev.NoLog)\n            {\n                ValidateWithAssetDatabase();\n            }\n            \n\n            if (shouldWriteImportLog && (fileSize >= MIN_FILE_SIZE_2LOG))\n            {\n                DateTime endTime = DateTime.Now;\n                double duration = (endTime - startTime).TotalMilliseconds;\n                var logMessage = $\", Duration: {duration} ms\";\n                File.AppendAllText(logPath, logMessage + Environment.NewLine);\n            }\n        }\n\n        internal void ValidateWithAssetDatabase()\n        {\n            if (IsMissing || IsFolder || type == AssetType.SCRIPT) return;\n            \n            try\n            {\n                // Get Unity's known dependencies\n\n                string[] unityDeps = AssetDatabase.GetDependencies(assetPath, false);\n                if (unityDeps == null) return;\n                var unityGuids = new HashSet<string>();\n                \n                foreach (string depPath in unityDeps)\n                {\n                    if (depPath == assetPath) continue; // Skip self-reference\n                    string depGuid = AssetDatabase.AssetPathToGUID(depPath);\n                    if (!string.IsNullOrEmpty(depGuid))\n                        unityGuids.Add(depGuid);\n                }\n                \n                // Compare with FR2's parsed results\n                var fr2Guids = new HashSet<string>(UseGUIDs.Keys);\n                var missingInFR2 = new List<string>();\n                \n                // Find guids in Unity but not in FR2\n                foreach (string unityGuid in unityGuids)\n                {\n                    if (!fr2Guids.Contains(unityGuid))\n                        missingInFR2.Add(unityGuid);\n                }\n                \n                if (missingInFR2.Count > 0 && extension != \".shadergraph\")\n                {\n                    AssetFinderLOG.LogWarning($\"AssetDatabase has {missingInFR2.Count} more dependencies than FR2 for '{assetPath}'. \" +\n                                   \"This may indicate unsaved changes or new asset types not handled by FR2 parser.\");\n                    \n                    // Add missing references to FR2's cache\n                    foreach (string missingGuid in missingInFR2)\n                    {\n                        AddUseGUID(missingGuid);\n                        AssetFinderLOG.Log($\"Add missingGUID: {missingGuid} --> {AssetDatabase.GUIDToAssetPath(missingGuid)}\");\n                    }\n                }\n            }\n            catch\n            {\n                AssetFinderLOG.LogWarning($\"Failed to validate dependencies for {assetPath}\");\n            }\n        }\n\n        internal void LoadYAML2()\n        {\n            if (!m_pathLoaded) LoadPathInfo();\n\n            if (!File.Exists(m_assetPath))\n            {\n                state = AssetState.MISSING;\n                return;\n            }\n\n            if (m_assetPath == \"ProjectSettings/EditorBuildSettings.asset\")\n            {\n                EditorBuildSettingsScene[] listScenes = EditorBuildSettings.scenes;\n                foreach (EditorBuildSettingsScene scene in listScenes)\n                {\n                    if (!scene.enabled) continue;\n                    string path = scene.path;\n                    string guid = AssetDatabase.AssetPathToGUID(path);\n\n                    AddUseGUID(guid, 0);\n\t\t\t\t\t// AssetFinderLOG.Log(\"AddScene: \" + path);\n                }\n            }\n\n            if (string.IsNullOrEmpty(extension))\n            {\n                AssetFinderLOG.LogWarning($\"Something wrong? <{m_extension}>\");\n            }\n\n            if (extension == \".spriteatlas\") // check for force include in build\n            {\n                var atlasAsset = AssetDatabase.LoadAssetAtPath<UnityObject>(m_assetPath);\n                if (atlasAsset != null)\n                {\n                    var so = new SerializedObject(atlasAsset);\n                    SerializedProperty prop = so.FindProperty(\"m_EditorData.bindAsDefault\");\n                    m_forceIncludeInBuild = prop.boolValue;\n                }\n            }\n            \n            AssetFinderParser.ReadContent(m_assetPath, AddUseGUID);\n        }\n\n        internal void LoadFolder()\n        {\n            if (!Directory.Exists(m_assetPath))\n            {\n                state = AssetState.MISSING;\n                return;\n            }\n\n            // do not analyse folders outside project\n            if (!m_assetPath.StartsWith(\"Assets/\")) return;\n\n            try\n            {\n                string[] files = Directory.GetFiles(m_assetPath);\n                string[] dirs = Directory.GetDirectories(m_assetPath);\n\n                foreach (string f in files)\n                {\n                    if (f.EndsWith(\".meta\", StringComparison.Ordinal)) continue;\n\n                    string fguid = AssetDatabase.AssetPathToGUID(f);\n                    if (string.IsNullOrEmpty(fguid)) continue;\n\n                    AddUseGUID(fguid);\n                }\n\n                foreach (string d in dirs)\n                {\n                    string fguid = AssetDatabase.AssetPathToGUID(d);\n                    if (string.IsNullOrEmpty(fguid)) continue;\n\n                    AddUseGUID(fguid);\n                }\n            }\n            catch (Exception e)\n            {\n                AssetFinderLOG.LogWarning(\"LoadFolder() error :: \" + e + \"\\n\" + assetPath);\n            }\n            finally\n            {\n\n                state = AssetState.MISSING;\n            }\n        }\n\n        internal void LoadBinaryAsset()\n        {\n            ClearUseGUIDs();\n\n            UnityObject assetData = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject));\n            if (assetData is GameObject go)\n            {\n                type = AssetType.MODEL;\n                LoadGameObject(go);\n                binaryLoaded += 10;\n            } else if (assetData is TerrainData terrainData)\n            {\n                type = AssetType.TERRAIN;\n                LoadTerrainData(terrainData);\n                binaryLoaded += 20;\n            } else if (assetData is LightingDataAsset lightAsset)\n            {\n                type = AssetType.LIGHTING_DATA;\n                LoadLightingData(lightAsset);\n                binaryLoaded += 20;\n            } else\n            {\n                LoadSerialized(assetData);\n                binaryLoaded++;\n            }\n\n\t\t\tAssetFinderLOG.Log(\"LoadBinaryAsset :: \" + assetData + \":\" + type);\n            if (binaryLoaded <= 30) return;\n            binaryLoaded = 0;\n            AssetFinderUnity.UnloadUnusedAssets();\n        }\n\n        internal void LoadGameObject(GameObject go)\n        {\n            Component[] compList = go.GetComponentsInChildren<Component>();\n            for (var i = 0; i < compList.Length; i++)\n            {\n                LoadSerialized(compList[i]);\n            }\n        }\n\n        internal void LoadSerialized(UnityObject target)\n        {\n            SerializedProperty[] props = AssetFinderUnity.xGetSerializedProperties(target, true);\n\n            for (var i = 0; i < props.Length; i++)\n            {\n                if (props[i].propertyType != SerializedPropertyType.ObjectReference) continue;\n\n                UnityObject refObj = props[i].objectReferenceValue;\n                if (refObj == null) continue;\n\n                string refGUID = AssetDatabase.AssetPathToGUID(\n                    AssetDatabase.GetAssetPath(refObj)\n                );\n\n                AddUseGUID(refGUID);\n            }\n        }\n\n        private void AddTextureGUID(SerializedProperty prop)\n        {\n            if (prop == null || prop.objectReferenceValue == null) return;\n            string path = AssetDatabase.GetAssetPath(prop.objectReferenceValue);\n            if (string.IsNullOrEmpty(path)) return;\n            AddUseGUID(AssetDatabase.AssetPathToGUID(path));\n        }\n\n        internal void LoadLightingData(LightingDataAsset asset)\n        {\n            foreach (Texture texture in AssetFinderLightmap.Read(asset))\n            {\n                if (texture == null) continue;\n                string path = AssetDatabase.GetAssetPath(texture);\n                string assetGUID = AssetDatabase.AssetPathToGUID(path);\n                if (!string.IsNullOrEmpty(assetGUID))\n                {\n                    AddUseGUID(assetGUID);\n                }\n            }\n        }\n\n        internal void LoadTerrainData(TerrainData terrain)\n        {\n#if UNITY_2018_3_OR_NEWER\n            TerrainLayer[] arr0 = terrain.terrainLayers;\n            for (var i = 0; i < arr0.Length; i++)\n            {\n                string aPath = AssetDatabase.GetAssetPath(arr0[i]);\n                string refGUID = AssetDatabase.AssetPathToGUID(aPath);\n                AddUseGUID(refGUID);\n            }\n#endif\n\n            DetailPrototype[] arr = terrain.detailPrototypes;\n\n            for (var i = 0; i < arr.Length; i++)\n            {\n                string aPath = AssetDatabase.GetAssetPath(arr[i].prototypeTexture);\n                string refGUID = AssetDatabase.AssetPathToGUID(aPath);\n                AddUseGUID(refGUID);\n            }\n\n            TreePrototype[] arr2 = terrain.treePrototypes;\n            for (var i = 0; i < arr2.Length; i++)\n            {\n                string aPath = AssetDatabase.GetAssetPath(arr2[i].prefab);\n                string refGUID = AssetDatabase.AssetPathToGUID(aPath);\n                AddUseGUID(refGUID);\n            }\n\n            AssetFinderTerrain.TerrainTextureData[] arr3 = AssetFinderTerrain.GetTerrainTextureDatas(terrain);\n            for (var i = 0; i < arr3.Length; i++)\n            {\n                AssetFinderTerrain.TerrainTextureData texs = arr3[i];\n                for (var k = 0; k < texs.textures.Length; k++)\n                {\n                    Texture2D tex = texs.textures[k];\n                    if (tex == null) continue;\n\n                    string aPath = AssetDatabase.GetAssetPath(tex);\n                    if (string.IsNullOrEmpty(aPath)) continue;\n\n                    string refGUID = AssetDatabase.AssetPathToGUID(aPath);\n                    if (string.IsNullOrEmpty(refGUID)) continue;\n\n                    AddUseGUID(refGUID);\n                }\n            }\n        }\n\n        internal static void ClearLog()\n        {\n            if (shouldWriteImportLog)\n            {\n                File.WriteAllText(logPath, string.Empty);\n            } else\n            {\n                if (File.Exists(logPath)) File.Delete(logPath);\n            }\n\n            scanStartTime = DateTime.Now;\n        }\n\n        internal static void WriteTotalScanTime()\n        {\n            if (!shouldWriteImportLog) return;\n            double totalScanTime = (DateTime.Now - scanStartTime).TotalSeconds;\n            File.AppendAllText(logPath, $\"\\nTotal scan time: {totalScanTime} seconds\\n\");\n        }\n\n        private void ClearUseGUIDs()\n        {\n\t\t    // AssetFinderLOG.Log(\"ClearUseGUIDs: \" + assetPath);\n            UseGUIDs.Clear();\n            UseGUIDsList.Clear();\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.ContentLoader.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8b4f01c105762d742adedeca5785b5ca\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Drawing.cs",
    "content": "using System;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        // ----------------------------- UI DRAWING & USER ACTIONS ---------------------------------------\n\n        internal class AssetFinderAssetDrawConfig\n        {\n            public bool highlight;\n            public bool drawPath = true;\n            public bool showFileSize = true;\n            public bool showABName = false;\n            public bool showAtlasName = false;\n            public bool showUsageIcon = true;\n            public IWindow window = null;\n            public bool drawExtension = true;\n            public Action onShowDetails = null;\n\n            public AssetFinderAssetDrawConfig(\n            bool highlight,\n            bool drawPath = true,\n            bool showFileSize = true,\n            bool showABName = false,\n            bool showAtlasName = false,\n            bool showUsageIcon = true,\n            IWindow window = null,\n            bool drawExtension = true,\n                Action onShowDetails = null)\n            {\n                this.highlight = highlight;\n                this.drawPath = drawPath;\n                this.showFileSize = showFileSize;\n                this.showABName = showABName;\n                this.showAtlasName = showAtlasName;\n                this.showUsageIcon = showUsageIcon;\n                this.window = window;\n                this.drawExtension = drawExtension;\n                this.onShowDetails = onShowDetails;\n            }\n        }\n\n        internal float Draw(\n            Rect r,\n            AssetFinderAssetDrawConfig cfg\n        )\n        {\n            Rect rowRect = new Rect(r.x, r.y, r.width, AssetFinderTheme.Current.TreeItemHeight);\n            bool isHover = rowRect.Contains(Event.current.mousePosition);\n            bool singleLine = r.height <= 18f;\n            float rw = r.width;\n            bool selected = AssetFinderBookmark.Contains(guid);\n\n            r.height = AssetFinderTheme.Current.TreeItemHeight;\n            bool hasMouse = (Event.current.type == EventType.MouseUp) && r.Contains(Event.current.mousePosition);\n\n            if (hasMouse && (Event.current.button == 1))\n            {\n                var menu = new GenericMenu();\n                if (m_extension == \".prefab\") menu.AddItem(AssetFinderGUIContent.FromString(\"Edit in Scene\"), false, EditPrefab);\n\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Open\"), false, Open);\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Ping\"), false, Ping);\n                #if UNITY_2022_3_OR_NEWER\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Properties...\"), false, OpenProperties);\n                #endif\n                menu.AddItem(AssetFinderGUIContent.FromString(guid), false, CopyGUID);\n\n                //menu.AddItem(AssetFinderGUIContent.FromString(\"Select in Project Panel\"), false, Select);\n\n                menu.AddSeparator(string.Empty);\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Copy path\"), false, CopyAssetPath);\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Copy full path\"), false, CopyAssetPathFull);\n\n                menu.ShowAsContext();\n                Event.current.Use();\n            }\n\n            if (IsMissing)\n            {\n                if (!singleLine) r.y += 16f;\n\n                if (Event.current.type != EventType.Repaint) return 0;\n\n                GUI.Label(r, AssetFinderGUIContent.FromString(guid), EditorStyles.whiteBoldLabel);\n                return 0;\n            }\n\n            Rect iconRect = GUI2.LeftRect(16f, ref r);\n            GUI2.LeftRect(2f, ref r);\n            if (Event.current.type == EventType.Repaint)\n            {\n                Texture icon = AssetDatabase.GetCachedIcon(m_assetPath);\n                if (icon != null) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit);\n            }\n\n            if ((Event.current.type == EventType.MouseDown) && (Event.current.button == 0))\n            {\n                Rect pingRect = iconRect; //AssetFinderSetting.PingRow ? new Rect(0, r.y, r.x + r.width, r.height) : \n                if (pingRect.Contains(Event.current.mousePosition))\n                {\n                    if (Event.current.control || Event.current.command)\n                    {\n                        if (selected)\n                        {\n                            RemoveFromSelection();\n                        } else\n                        {\n                            AddToSelection();\n                        }\n\n                        if (cfg.window != null) cfg.window.Repaint();\n                    } else if (Event.current.clickCount == 2)\n                    {\n                        Open();\n                        Event.current.Use();\n                    } else\n                    {\n                        Ping();\n                    }\n                }\n            }\n        \n            if (isHover)\n            {\n                if (cfg.onShowDetails != null)\n                {\n                    r.xMax -= 10f;\n                    var (detailRect, flex) = r.ExtractRight(22f);\n                    if (GUI.Button(detailRect, new GUIContent(\"...\", \"Show Details\"), EditorStyles.miniButton))\n                    {\n                        cfg.onShowDetails?.Invoke();\n                    }\n                    r = flex;\n                }\n                \n#if UNITY_2022_3_OR_NEWER\n                var (propRect, flex1) = r.ExtractRight(22f);\n                if (GUI.Button(propRect, new GUIContent(\"P\", \"Open Properties\"), EditorStyles.miniButton))\n                {\n                    OpenProperties();\n                }\n                r = flex1;\n#endif\n            }\n\n            if (Event.current.type != EventType.Repaint) return 0;\n            if ((UsedByMap != null) && (UsedByMap.Count > 0))\n            {\n                GUIContent str = AssetFinderGUIContent.FromInt(UsedByMap.Count);\n                Rect countRect = iconRect;\n                countRect.x -= 16f;\n                countRect.xMin = -10f;\n                GUI.Label(countRect, str, GUI2.miniLabelAlignRight);\n            }\n\n            float pathW = cfg.drawPath && !string.IsNullOrEmpty(assetFolder)\n                ? EditorStyles.miniLabel.CalcSize(AssetFinderGUIContent.FromString(assetFolder)).x\n                : 8f;\n\n            float nameW = cfg.drawPath\n                ? EditorStyles.boldLabel.CalcSize(AssetFinderGUIContent.FromString(assetName)).x\n                : EditorStyles.label.CalcSize(AssetFinderGUIContent.FromString(assetName)).x;\n\n            float extW = string.IsNullOrEmpty(extension) ? 0f : EditorStyles.miniLabel.CalcSize(AssetFinderGUIContent.FromString(extension)).x;\n            Color cc = GUI.skin.settings.selectionColor;\n\n            if (singleLine)\n            {\n                Rect lbRect = GUI2.LeftRect(pathW + nameW + extW, ref r);\n\n                if (selected)\n                {\n                    Color c1 = GUI.color;\n                    GUI.color = cc;\n                    GUI.DrawTexture(lbRect, EditorGUIUtility.whiteTexture);\n                    GUI.color = c1;\n                }\n\n                if (cfg.drawPath)\n                {\n                    if (!string.IsNullOrEmpty(assetFolder))\n                    {\n                        Color c2 = GUI.color;\n                        GUI.color = new Color(c2.r, c2.g, c2.b, c2.a * 0.5f);\n                        GUI.Label(GUI2.LeftRect(pathW, ref lbRect), AssetFinderGUIContent.FromString(assetFolder), EditorStyles.miniLabel);\n                        GUI.color = c2;\n                    }\n\n                    GUI.Label(lbRect, AssetFinderGUIContent.FromString(assetName), EditorStyles.boldLabel);\n                } else\n                {\n                    GUI.Label(lbRect, AssetFinderGUIContent.FromString(assetName), EditorStyles.label);\n                }\n\n                lbRect.xMin += nameW - 2f;\n                lbRect.y += 1f;\n\n                if (!string.IsNullOrEmpty(extension) && cfg.drawExtension)\n                {\n                    Color c3 = GUI.color;\n                    GUI.color = new Color(c3.r, c3.g, c3.b, c3.a * 0.7f);\n                    GUI.Label(lbRect, AssetFinderGUIContent.FromString(extension), EditorStyles.miniLabel);\n                    GUI.color = c3;\n                }\n            } else\n            {\n                if (cfg.drawPath) GUI.Label(new Rect(r.x, r.y + 16f, r.width, r.height), AssetFinderGUIContent.FromString(m_assetFolder), EditorStyles.miniLabel);\n                Rect lbRect = GUI2.LeftRect(nameW, ref r);\n                if (selected) GUI2.Rect(lbRect, cc);\n                GUI.Label(lbRect, AssetFinderGUIContent.FromString(assetName), EditorStyles.boldLabel);\n            }\n\n            Rect rr = GUI2.RightRect(10f, ref r);\n            if (cfg.highlight)\n            {\n                rr.xMin += 2f;\n                rr.width = 1f;\n                GUI2.Rect(rr, GUI2.darkGreen);\n            }\n\n            Color c = GUI.color;\n            GUI.color = new Color(c.r, c.g, c.b, c.a * 0.5f);\n\n            // (Properties button drawn earlier to receive click events)\n\n            if (cfg.showFileSize)\n            {\n                Rect fsRect = GUI2.RightRect(40f, ref r);\n                if (fileSizeText == null) fileSizeText = AssetFinderGUIContent.FromString(AssetFinderHelper.GetfileSizeString(fileSize));\n                GUI.Label(fsRect, fileSizeText, GUI2.miniLabelAlignRight);\n            }\n\n            if (!string.IsNullOrEmpty(m_addressable))\n            {\n                Rect adRect = GUI2.RightRect(100f, ref r);\n                GUI.Label(adRect, AssetFinderGUIContent.FromString(m_addressable), GUI2.miniLabelAlignRight);\n            }\n\n            if (cfg.showUsageIcon && (HashUsedByClassesIds != null))\n            {\n                foreach (int item in HashUsedByClassesIds)\n                {\n                    if (!AssetFinderUnity.HashClassesNormal.ContainsKey(item)) continue;\n\n                    string name = AssetFinderUnity.HashClassesNormal[item];\n                    if (!HashClasses.TryGetValue(item, out Type t))\n                    {\n                        t = AssetFinderUnity.GetType(name);\n                        HashClasses.Add(item, t);\n                    }\n\n                    bool isExisted = cacheImage.TryGetValue(name, out GUIContent content);\n                    if (content == null)\n                    {\n                        content = t == null ? GUIContent.none : AssetFinderGUIContent.FromType(t, name);\n                    }\n\n                    if (!isExisted)\n                    {\n                        cacheImage.Add(name, content);\n                    } else\n                    {\n                        cacheImage[name] = content;\n                    }\n\n                    if (content != null)\n                    {\n                        try\n                        {\n                            GUI.Label(GUI2.RightRect(15f, ref r), content, GUI2.miniLabelAlignRight);\n                        }\n\t\t\t\t\t\tcatch (Exception e)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tAssetFinderLOG.LogWarning(e);\n\t\t\t\t\t\t}\n                    }\n                }\n            }\n\n            if (cfg.showAtlasName)\n            {\n                GUI2.RightRect(10f, ref r);\n                Rect abRect = GUI2.RightRect(120f, ref r);\n                if (!string.IsNullOrEmpty(m_atlas)) GUI.Label(abRect, AssetFinderGUIContent.FromString(m_atlas), GUI2.miniLabelAlignRight);\n            }\n\n            if (cfg.showABName)\n            {\n                GUI2.RightRect(10f, ref r);\n                Rect abRect = GUI2.RightRect(100f, ref r);\n                if (!string.IsNullOrEmpty(m_assetbundle)) GUI.Label(abRect, AssetFinderGUIContent.FromString(m_assetbundle), GUI2.miniLabelAlignRight);\n            }\n\n            if (true)\n            {\n                GUI2.RightRect(10f, ref r);\n                Rect abRect = GUI2.RightRect(100f, ref r);\n                if (!string.IsNullOrEmpty(m_addressable)) GUI.Label(abRect, AssetFinderGUIContent.FromString(m_addressable), GUI2.miniLabelAlignRight);\n            }\n\n            GUI.color = c;\n\n            if (Event.current.type == EventType.Repaint) return rw < pathW + nameW ? 32f : 18f;\n\n            return r.height;\n        }\n\n        internal GenericMenu AddArray(\n            GenericMenu menu, System.Collections.Generic.List<string> list, string prefix, string title,\n            string emptyTitle, bool showAsset, int max = 10)\n        {\n            menu.AddItem(AssetFinderGUIContent.FromString(emptyTitle), true, null);\n            return menu;\n        }\n\n        internal void CopyGUID()\n        {\n            EditorGUIUtility.systemCopyBuffer = guid;\n            Debug.Log(guid);\n        }\n\n        internal void CopyName()\n        {\n            EditorGUIUtility.systemCopyBuffer = m_assetName;\n            Debug.Log(m_assetName);\n        }\n\n        internal void CopyAssetPath()\n        {\n            EditorGUIUtility.systemCopyBuffer = m_assetPath;\n            Debug.Log(m_assetPath);\n        }\n\n        internal void CopyAssetPathFull()\n        {\n            string fullName = new FileInfo(m_assetPath).FullName;\n            EditorGUIUtility.systemCopyBuffer = fullName;\n            Debug.Log(fullName);\n        }\n\n\n        internal void RemoveFromSelection()\n        {\n            if (AssetFinderBookmark.Contains(guid)) AssetFinderBookmark.Remove(guid);\n        }\n\n        internal void AddToSelection()\n        {\n            if (!AssetFinderBookmark.Contains(guid)) AssetFinderBookmark.Add(guid);\n        }\n\n        internal void Ping()\n        {\n            if (EditorWindow.focusedWindow is AssetFinderWindowAll fr2Window)\n            {\n                fr2Window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Asset);    \n            }\n            \n            EditorApplication.delayCall += () =>\n            {\n                var asset = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject));\n                if (asset != null)\n                {\n                    EditorGUIUtility.PingObject(asset);\n                }\n            };\n\n            // Only use event if it exists (not null when called from context menu)\n            if (Event.current != null)\n            {\n                Event.current.Use();\n            }\n        }\n\n        internal void Open()\n        {\n            AssetDatabase.OpenAsset(\n                AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject))\n            );\n        }\n\n        internal void OpenProperties()\n        {\n#if UNITY_2022_3_OR_NEWER\n            var obj = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject));\n            if (obj != null)\n            {\n                EditorUtility.OpenPropertyEditor(obj);\n            }\n#endif\n        }\n\n\n        internal void EditPrefab()\n        {\n            UnityObject prefab = AssetDatabase.LoadAssetAtPath(m_assetPath, typeof(UnityObject));\n            UnityObject.Instantiate(prefab);\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.Drawing.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 92421bd9e4cef8a4e969c1da1c6f6769\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.FileInfo.cs",
    "content": "using System;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        // ----------------------- FILE INFO ------------------------\n\n        public bool fileInfoDirty => type == AssetType.UNKNOWN || m_fileInfoReadTS <= m_assetChangeTS;\n        public bool fileContentDirty => (m_fileWriteTS != m_cachefileWriteTS) && !isBuiltIn;\n        public bool isDirty => (fileInfoDirty || fileContentDirty) && !isBuiltIn;\n        public bool isBuiltIn => type == AssetType.BUILT_IN;\n        public bool hasBeenScanned => m_cachefileWriteTS > 0 || isBuiltIn;\n\n        internal string fileInfoHash => LoadFileInfo().m_fileInfoHash;\n        internal long fileSize => LoadFileInfo().m_fileSize;\n        public string AtlasName => LoadFileInfo().m_atlas;\n        public string AssetBundleName => LoadFileInfo().m_assetbundle;\n        public string AddressableName => LoadFileInfo().m_addressable;\n\n        private bool ExistOnDisk()\n        {\n            if (isBuiltIn) return true;\n            if (IsMissing) return false; // asset not exist - no need to check FileSystem!\n            if (type == AssetType.FOLDER || type == AssetType.UNKNOWN)\n            {\n                if (Directory.Exists(m_assetPath))\n                {\n                    if (type == AssetType.UNKNOWN) type = AssetType.FOLDER;\n                    return true;\n                }\n\n                if (type == AssetType.FOLDER) return false;\n            }\n\n            // must be file here\n            if (!File.Exists(m_assetPath)) return false;\n\n            if (type == AssetType.UNKNOWN) GuessAssetType();\n            return true;\n        }\n\n        internal AssetFinderAsset LoadFileInfo()\n        {\n            if (!fileInfoDirty) return this;\n            if (string.IsNullOrEmpty(m_assetPath)) LoadPathInfo(); // always reload Path Info\n\n            m_fileInfoReadTS = AssetFinderUnity.Epoch(DateTime.Now);\n            if (isBuiltIn) return this;\n            if (IsMissing)\n            {\n                return this;\n            }\n\n            if (!ExistOnDisk())\n            {\n                state = AssetState.MISSING;\n                return this;\n            }\n\n            if (type == AssetType.FOLDER) return this; // nothing to read\n\n            Type assetType = AssetDatabase.GetMainAssetTypeAtPath(m_assetPath);\n            if (assetType == typeof(AssetFinderCache)) return this;\n\n            var info = new FileInfo(m_assetPath);\n            m_fileSize = info.Length;\n            m_fileInfoHash = info.Length + info.Extension;\n            m_addressable = AssetFinderUnity.GetAddressable(guid);\n\n            m_assetbundle = AssetDatabase.GetImplicitAssetBundleName(m_assetPath);\n\n            if (assetType == typeof(Texture2D))\n            {\n                AssetImporter importer = AssetImporter.GetAtPath(m_assetPath);\n                if (importer is TextureImporter tImporter)\n                {\n                    #pragma warning disable CS0618\n                    if (tImporter.qualifiesForSpritePacking) m_atlas = tImporter.spritePackingTag;\n                    #pragma warning restore CS0618\n                }\n            }\n\n            // check if file content changed\n            var metaInfo = new FileInfo(m_assetPath + \".meta\");\n            int assetTime = AssetFinderUnity.Epoch(info.LastWriteTime);\n            int metaTime = AssetFinderUnity.Epoch(metaInfo.LastWriteTime);\n\n            // update fileChangeTimeStamp\n            m_fileWriteTS = Mathf.Max(metaTime, assetTime);\n            return this;\n        }\n\n        internal void GuessAssetType()\n        {\n            var ext = extension.ToLowerInvariant();\n            if (SCRIPT_EXTENSIONS.Contains(ext))\n            {\n                type = AssetType.SCRIPT;\n            } else if (REFERENCABLE_EXTENSIONS.Contains(ext))\n            {\n                bool isUnity = ext == \".unity\";\n                type = isUnity ? AssetType.SCENE : AssetType.REFERENCABLE;\n\n                if (ext == \".asset\" || isUnity || ext == \".spriteatlas\")\n                {\n                    var buffer = new byte[5];\n                    FileStream stream = null;\n\n                    try\n                    {\n                        stream = File.OpenRead(m_assetPath);\n                        stream.Read(buffer, 0, 5);\n                        stream.Close();\n                    }\n#if AssetFinderDEBUG\n                    catch (Exception e)\n                    {\n                        AssetFinderLOG.LogWarning(\"Guess Asset Type error :: \" + e + \"\\n\" + m_assetPath);\n#else\n                    catch\n                    {\n#endif\n                        if (stream != null) stream.Close();\n                        state = AssetState.MISSING;\n                        return;\n                    } finally\n                    {\n                        if (stream != null) stream.Close();\n                    }\n\n                    var str = string.Empty;\n                    foreach (byte t in buffer)\n                    {\n                        str += (char)t;\n                    }\n\n                    if (str != \"%YAML\") type = AssetType.BINARY_ASSET;\n                }\n            } else if (REFERENCABLE_JSON.Contains(ext) || UI_TOOLKIT.Contains(ext))\n            {\n                type = AssetType.REFERENCABLE;\n            } else if (REFERENCABLE_META.Contains(ext))\n            {\n                type = AssetType.REFERENCABLE;\n            } else if (ext == \".fbx\")\n            {\n                type = AssetType.MODEL;\n            } else if (ext == \".dll\")\n            {\n                type = AssetType.DLL;\n            } else\n            {\n                type = AssetType.NON_READABLE;\n            }\n        }\n\n        internal void MarkAsDirty(bool isMoved = true, bool force = false)\n        {\n            if (isMoved)\n            {\n                string newPath = AssetDatabase.GUIDToAssetPath(guid);\n                if (newPath != m_assetPath)\n                {\n                    m_pathLoaded = false;\n                    m_assetPath = newPath;\n                }\n            }\n\n            state = AssetState.CACHE;\n            m_assetChangeTS = AssetFinderUnity.Epoch(DateTime.Now); // re-read FileInfo\n            if (force) m_cachefileWriteTS = 0;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.FileInfo.cs.meta",
    "content": "fileFormatVersion: 2\nguid: def6a6c199d5b5c44b9920f983b64d92\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.GuidManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        // ----------------------------- GUID MANAGEMENT ---------------------------------------\n\n        public Dictionary<string, HashSet<long>> UseGUIDs\n        {\n            get\n            {\n                if (_UseGUIDs != null) return _UseGUIDs;\n\n                _UseGUIDs = new Dictionary<string, HashSet<long>>(UseGUIDsList.Count);\n                for (var i = 0; i < UseGUIDsList.Count; i++)\n                {\n                    string guid = UseGUIDsList[i].guid;\n                    if (_UseGUIDs.ContainsKey(guid))\n                    {\n                        for (var j = 0; j < UseGUIDsList[i].ids.Count; j++)\n                        {\n                            long val = UseGUIDsList[i].ids[j];\n                            if (_UseGUIDs[guid].Contains(val)) continue;\n\n                            _UseGUIDs[guid].Add(UseGUIDsList[i].ids[j]);\n                        }\n                    } else\n                    {\n                        _UseGUIDs.Add(guid, new HashSet<long>(UseGUIDsList[i].ids));\n                    }\n                }\n\n                return _UseGUIDs;\n            }\n        }\n\n        internal void AddUseGUID(string fguid, long fFileId = -1)\n        {\n            AddUseGUID(fguid, fFileId, true);\n        }\n\n        internal void AddUseGUID(string fguid, long fFileId, bool checkExist)\n        {\n            // if (checkExist && UseGUIDs.ContainsKey(fguid)) return;\n            if (!IsValidGUID(fguid)) return;\n\n            if (!UseGUIDs.ContainsKey(fguid))\n            {\n                UseGUIDsList.Add(new Classes\n                {\n                    guid = fguid,\n                    ids = new List<long>()\n                });\n                UseGUIDs.Add(fguid, new HashSet<long>());\n            }\n\n            if (fFileId == -1) return;\n            if (UseGUIDs[fguid].Contains(fFileId)) return;\n\n            UseGUIDs[fguid].Add(fFileId);\n            Classes i = UseGUIDsList.FirstOrDefault(x => x.guid == fguid);\n            if (i != null) i.ids.Add(fFileId);\n        }\n\n        public void AddUsedBy(string guid, AssetFinderAsset asset)\n        {\n            if (UsedByMap.ContainsKey(guid)) return;\n\n            if (guid == this.guid)\n            {\n                return;\n            }\n\n            UsedByMap.Add(guid, asset);\n            if (HashUsedByClassesIds == null) HashUsedByClassesIds = new HashSet<long>();\n\n            if (asset.UseGUIDs.TryGetValue(this.guid, out HashSet<long> output))\n            {\n                foreach (int item in output)\n                {\n                    HashUsedByClassesIds.Add(item);\n                }\n            }\n        }\n\n        public int UsageCount()\n        {\n            return UsedByMap.Count;\n        }\n\n        public int UseGUIDsCount\n        {\n            get\n            {\n                // Return 0 for ignored assets and package assets because we don't scan their content\n                if (IsExcluded || inPackages)\n                {\n                    return 0;\n                }\n                return UseGUIDs.Count;\n            }\n        }\n        public string DebugUseGUID()\n        {\n            return $\"{guid} : {assetPath}\\n{string.Join(\"\\n\", UseGUIDsList.Select(item => item.guid).ToArray())}\";\n        }\n\n        internal static bool IsValidGUID(string guid)\n        {\n            return AssetDatabase.GUIDToAssetPath(guid) != AssetFinderCache.CachePath; // just skip AssetFinderCache asset\n        }\n\n        internal static List<string> FindUsageGUIDs(AssetFinderAsset asset, bool includeScriptSymbols)\n        {\n            var result = new HashSet<string>();\n            if (asset == null)\n            {\n                AssetFinderLOG.LogWarning(\"Asset invalid : \" + asset.m_assetName);\n                return result.ToList();\n            }\n\n            foreach (KeyValuePair<string, HashSet<long>> item in asset.UseGUIDs)\n            {\n                result.Add(item.Key);\n            }\n\n            return result.ToList();\n        }\n\n        internal static List<string> FindUsedByGUIDs(AssetFinderAsset asset)\n        {\n            return asset.UsedByMap.Keys.ToList();\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.GuidManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9bb02cbb695900d4b91c00fbee372c7d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.PathInfo.cs",
    "content": "using System;\nusing System.Globalization;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderAsset\n    {\n        // ----------------------- PATH INFO ------------------------\n\n        [NonSerialized] private string m_assetFolder;\n        [NonSerialized] private string m_assetName;\n        [NonSerialized] private string m_assetPath;\n        [NonSerialized] private string m_extension;\n        [NonSerialized] private bool m_inEditor;\n        [NonSerialized] private bool m_inPackage;\n        [NonSerialized] private bool m_inPlugins;\n        [NonSerialized] private bool m_inResources;\n        [NonSerialized] private bool m_inStreamingAsset;\n        [NonSerialized] private bool m_pathLoaded;\n\n        public string assetName => LoadPathInfo().m_assetName;\n        public string assetPath\n        {\n            get\n            {\n                if (!string.IsNullOrEmpty(m_assetPath)) return m_assetPath;\n                m_assetPath = AssetDatabase.GUIDToAssetPath(guid);\n                if (string.IsNullOrEmpty(m_assetPath)) state = AssetState.MISSING;\n                return m_assetPath;\n            }\n        }\n\n        public string parentFolderPath => LoadPathInfo().m_assetFolder;\n        public string assetFolder => LoadPathInfo().m_assetFolder;\n        public string extension => LoadPathInfo().m_extension;\n        public bool inEditor => LoadPathInfo().m_inEditor;\n        public bool inPlugins => LoadPathInfo().m_inPlugins;\n        public bool inPackages => LoadPathInfo().m_inPackage;\n        public bool inResources => LoadPathInfo().m_inResources;\n        public bool inStreamingAsset => LoadPathInfo().m_inStreamingAsset;\n\n        internal bool IsExcluded\n        {\n            get\n            {\n                if (excludeTS >= ignoreTS) return _isExcluded;\n\n                excludeTS = ignoreTS;\n                _isExcluded = false;\n\n                var h = AssetFinderSetting.IgnoreAsset;\n                foreach (string item in h)\n                {\n                    if (!m_assetPath.StartsWith(item, false, CultureInfo.InvariantCulture)) continue;\n                    _isExcluded = true;\n                    return true;\n                }\n\n                return false;\n            }\n        }\n\n        public AssetFinderAsset LoadPathInfo()\n        {\n            if (m_pathLoaded) return this;\n            m_pathLoaded = true;\n\n            m_assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(assetPath))\n            {\n                state = AssetState.MISSING;\n                return this;\n            }\n\n// #if AssetFinderDEBUG\n// \t\t\tAssetFinderLOG.Log(\"LoadPathInfo ... \" + fileInfoHash + \":\" + AssetDatabase.GUIDToAssetPath(guid));\n// #endif\n            AssetFinderUnity.SplitPath(m_assetPath, out m_assetName, out m_extension, out m_assetFolder);\n\n            if (m_assetFolder.StartsWith(\"Assets/\"))\n            {\n                m_assetFolder = m_assetFolder.Substring(7);\n            } else if (!AssetFinderUnity.StringStartsWith(m_assetPath,\"Project Settings/\", \"Library/\")) m_assetFolder = \"built-in/\";\n\n            m_inEditor = m_assetPath.Contains(\"/Editor/\") || m_assetPath.Contains(\"/Editor Default Resources/\");\n            m_inResources = m_assetPath.Contains(\"/Resources/\");\n            m_inStreamingAsset = m_assetPath.Contains(\"/StreamingAssets/\");\n            m_inPlugins = m_assetPath.Contains(\"/Plugins/\");\n            m_inPackage = m_assetPath.StartsWith(\"Packages/\");\n            return this;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.PathInfo.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aeaa48e4ac2b35e43951fa13a606b81c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.cs",
    "content": "#if AssetFinderADDRESSABLE\nusing UnityEditor.AddressableAssets;\nusing UnityEngine.AddressableAssets;\n#endif\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Serialization;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n    [Serializable]\n    internal partial class AssetFinderAsset\n    {\n\n        // Constants moved to AssetFinderAsset.Constants.cs\n\n        // ----------------------------- DRAW  ---------------------------------------\n\n        [SerializeField] public string guid;\n\n        // Need to read FileInfo: soft-cache (always re-read when needed)\n        [FormerlySerializedAs(\"type2\")] [SerializeField] public AssetType type;\n        [SerializeField] private string m_fileInfoHash;\n        [SerializeField] private string m_assetbundle;\n        [SerializeField] private string m_addressable;\n\n        [SerializeField] private string m_atlas;\n        [SerializeField] private long m_fileSize;\n\n        [SerializeField] private int m_assetChangeTS; // Realtime when asset changed (trigger by import asset operation)\n        [SerializeField] private int m_fileInfoReadTS; // Realtime when asset being read\n\n        [SerializeField] private int m_fileWriteTS; // file's lastModification (file content + meta)\n        [SerializeField] private int m_cachefileWriteTS; // file's lastModification at the time the content being read\n        [SerializeField] private bool m_forceIncludeInBuild;\n\n        [SerializeField] internal int refreshStamp; // use to check if asset has been deleted (refreshStamp not updated)\n        [SerializeField] internal List<Classes> UseGUIDsList = new List<Classes>();\n\n        private bool _isExcluded;\n        private Dictionary<string, HashSet<long>> _UseGUIDs;\n        private float excludeTS;\n\n\n        // ----------------------------- DRAW  ---------------------------------------\n        [NonSerialized] private GUIContent fileSizeText;\n        internal HashSet<long> HashUsedByClassesIds = new HashSet<long>();\n        // Path info moved to AssetFinderAsset.PathInfo.cs\n\n\n        // Do not cache\n        [NonSerialized] internal AssetState state;\n        internal Dictionary<string, AssetFinderAsset> UsedByMap = new Dictionary<string, AssetFinderAsset>();\n\n        public AssetFinderAsset(string guid)\n        {\n            this.guid = guid;\n            type = BUILT_IN_ASSETS.Contains(guid) ? AssetType.BUILT_IN : AssetType.UNKNOWN;\n        }\n\n        public bool forcedIncludedInBuild => m_forceIncludeInBuild;\n\n        // ----------------------- TYPE INFO ------------------------\n\n        internal bool IsFolder => type == AssetType.FOLDER;\n        internal bool IsScript => type == AssetType.SCRIPT;\n        internal bool IsMissing => (state == AssetState.MISSING) && !isBuiltIn;\n\n        internal bool IsReferencable => type == AssetType.REFERENCABLE ||\n            type == AssetType.SCENE;\n\n        internal bool IsBinaryAsset => type == AssetType.BINARY_ASSET ||\n            type == AssetType.MODEL ||\n            type == AssetType.TERRAIN ||\n            type == AssetType.LIGHTING_DATA;\n        // ------------------------------- GETTERS -----------------------------\n\n        internal bool IsCriticalAsset()\n        {\n            // Packages assets are always non-critical\n            if (string.IsNullOrEmpty(assetPath)) //  && assetPath.StartsWith(\"Packages/\")\n            {\n                return false;\n            }\n\n            if (AssetDatabase.IsValidFolder(assetPath))\n            {\n                return false;\n            }\n\n            if (type == AssetType.UNKNOWN) GuessAssetType();\n            \n            // Fast checks on asset type\n            switch (type)\n            {\n                case AssetType.REFERENCABLE:\n                case AssetType.SCENE:\n                case AssetType.BINARY_ASSET:\n                case AssetType.MODEL:\n                case AssetType.TERRAIN:\n                case AssetType.LIGHTING_DATA:\n                return true;\n\n                case AssetType.FOLDER:\n                case AssetType.SCRIPT:\n                case AssetType.DLL:\n                case AssetType.NON_READABLE:\n                {\n                    // if (assetPath.Contains(\".png\")) AssetFinderLOG.LogWarning($\"Wrong assetType? {type}\");\n                    return false;\n                }\n            }\n\n            if (string.IsNullOrEmpty(extension))\n            {\n                // if (assetPath.Contains(\".png\")) AssetFinderLOG.LogWarning($\"Wrong extensions? {extension}\");\n                return false;\n            }\n\n            var result = !NON_REFERENCE_EXTENSIONS.Contains(extension);\n            // if (assetPath.Contains(\".png\")) AssetFinderLOG.LogWarning($\"Result = {result}\");\n            return result;\n        }\n\n        // GUID management methods moved to AssetFinderAsset.GuidManager.cs\n\n        public override string ToString()\n        {\n            return $\"AssetFinderAsset[{m_assetName}]\";\n        }\n\n        // AddUseGUID methods moved to AssetFinderAsset.GuidManager.cs\n\n        // ----------------------------- STATIC  ---------------------------------------\n\n        internal static int SortByExtension(AssetFinderAsset a1, AssetFinderAsset a2)\n        {\n            if (a1 == null) return -1;\n            if (a2 == null) return 1;\n\n            int result = string.Compare(a1.m_extension, a2.m_extension, StringComparison.Ordinal);\n            return result == 0 ? string.Compare(a1.m_assetName, a2.m_assetName, StringComparison.Ordinal) : result;\n        }\n\n        internal static List<AssetFinderAsset> FindUsage(AssetFinderAsset asset)\n        {\n            if (asset == null) return null;\n\n            List<AssetFinderAsset> refs = AssetFinderCache.Api.FindAssets(asset.UseGUIDs.Keys.ToArray(), true);\n\n\n            return refs;\n        }\n\n        internal static List<AssetFinderAsset> FindUsedBy(AssetFinderAsset asset)\n        {\n            return asset.UsedByMap.Values.ToList();\n        }\n        \n        // ----------------------------- REPLACE GUIDS ---------------------------------------\n\n        internal bool ReplaceReference(string fromGUID, string toGUID, TerrainData terrain = null)\n        {\n            if (IsMissing) return false;\n\n            if (IsReferencable)\n            {\n                if (!File.Exists(m_assetPath))\n                {\n                    state = AssetState.MISSING;\n                    return false;\n                }\n\n                try\n                {\n                    string text = File.ReadAllText(m_assetPath).Replace(\"\\r\", \"\\n\");\n                    File.WriteAllText(m_assetPath, text.Replace(fromGUID, toGUID));\n                    return true;\n                } catch (Exception e)\n                {\n                    state = AssetState.MISSING;\n                    AssetFinderLOG.LogWarning(\"Replace Reference error :: \" + e + \"\\n\" + m_assetPath);\n                }\n\n                return false;\n            }\n\n            if (type == AssetType.TERRAIN)\n            {\n                var fromObj = AssetFinderUnity.LoadAssetWithGUID<UnityObject>(fromGUID);\n                var toObj = AssetFinderUnity.LoadAssetWithGUID<UnityObject>(toGUID);\n                var found = 0;\n\n                if (fromObj is Texture2D tex)\n                {\n                    DetailPrototype[] arr = terrain.detailPrototypes;\n                    for (var i = 0; i < arr.Length; i++)\n                    {\n                        if (arr[i].prototypeTexture != tex) continue;\n                        found++;\n                        arr[i].prototypeTexture = (Texture2D)toObj;\n                    }\n\n                    terrain.detailPrototypes = arr;\n                    AssetFinderTerrain.ReplaceTerrainTextureDatas(terrain, tex, (Texture2D)toObj);\n                }\n\n                if (fromObj is GameObject go)\n                {\n                    TreePrototype[] arr2 = terrain.treePrototypes;\n                    for (var i = 0; i < arr2.Length; i++)\n                    {\n                        if (arr2[i].prefab != go) continue;\n                        found++;\n                        arr2[i].prefab = (GameObject)toObj;\n                    }\n\n                    terrain.treePrototypes = arr2;\n                }\n\n                return found > 0;\n            }\n\n            AssetFinderLOG.LogWarning(\"Something wrong, should never be here - Ignored <\" + m_assetPath + \"> : not a readable type, can not replace ! \" + type);\n            return false;\n        }\n\n        internal string ReplaceFileIdIfNeeded(string line, long toFileId)\n        {\n            const string FileID = \"fileID: \";\n            int index = line.IndexOf(FileID, StringComparison.Ordinal);\n            if (index < 0 || toFileId <= 0) return line;\n            int startIndex = index + FileID.Length;\n            int endIndex = line.IndexOf(',', startIndex);\n            if (endIndex > startIndex)\n            {\n                string fromFileId = line.Substring(startIndex, endIndex - startIndex);\n                if (long.TryParse(fromFileId, out long fileType) &&\n                    fileType.ToString().StartsWith(toFileId.ToString().Substring(0, 3)))\n                {\n                    AssetFinderLOG.Log($\"ReplaceReference: fromFileId {fromFileId} to File Id {toFileId}\");\n                    return line.Replace(fromFileId, toFileId.ToString());\n                }\n                AssetFinderLOG.LogWarning($\"[Skip] Difference file type: {fromFileId} -> {toFileId}\");\n            } else\n            {\n                AssetFinderLOG.LogWarning(\"Cannot parse fileID in the line.\");\n            }\n            return line;\n        }\n\n        internal bool ReplaceReference(string fromGUID, string toGUID, long toFileId, TerrainData terrain = null)\n        {\n            if (IsMissing)\n            {\n                return false;\n            }\n\n            if (IsReferencable)\n            {\n                if (!File.Exists(m_assetPath))\n                {\n                    state = AssetState.MISSING;\n                    return false;\n                }\n\n                try\n                {\n                    var sb = new StringBuilder();\n                    string text = File.ReadAllText(assetPath);\n                    var currentIndex = 0;\n\n                    while (currentIndex < text.Length)\n                    {\n                        int lineEndIndex = text.IndexOfAny(new[] { '\\r', '\\n' }, currentIndex);\n                        if (lineEndIndex == -1)\n                        {\n                            lineEndIndex = text.Length;\n                        }\n\n                        string line = text.Substring(currentIndex, lineEndIndex - currentIndex);\n\n                        // Check if the line contains the GUID and possibly the fileID\n                        if (line.Contains(fromGUID))\n                        {\n                            line = ReplaceFileIdIfNeeded(line, toFileId);\n                            line = line.Replace(fromGUID, toGUID);\n                        }\n\n                        sb.Append(line);\n\n                        // Skip through any EOL characters\n                        while (lineEndIndex < text.Length)\n                        {\n                            char c = text[lineEndIndex];\n                            if (c == '\\r' || c == '\\n')\n                            {\n                                sb.Append(c);\n                                lineEndIndex++;\n                            }\n                            break;\n                        }\n\n                        currentIndex = lineEndIndex;\n                    }\n\n                    File.WriteAllText(assetPath, sb.ToString());\n                    //AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.Default);\n                    return true;\n                } catch (Exception e)\n                {\n                    state = AssetState.MISSING;\n                    AssetFinderLOG.LogWarning(\"Replace Reference error :: \" + e + \"\\n\" + m_assetPath);\n                }\n\n                return false;\n            }\n\n            if (type == AssetType.TERRAIN)\n            {\n                var fromObj = AssetFinderUnity.LoadAssetWithGUID<UnityObject>(fromGUID);\n                var toObj = AssetFinderUnity.LoadAssetWithGUID<UnityObject>(toGUID);\n                var found = 0;\n\n                // var terrain = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Object)) as TerrainData;\n\n                if (fromObj is Texture2D)\n                {\n                    DetailPrototype[] arr = terrain.detailPrototypes;\n                    for (var i = 0; i < arr.Length; i++)\n                    {\n                        if (arr[i].prototypeTexture == (Texture2D)fromObj)\n                        {\n                            found++;\n                            arr[i].prototypeTexture = (Texture2D)toObj;\n                        }\n                    }\n\n                    terrain.detailPrototypes = arr;\n                    AssetFinderTerrain.ReplaceTerrainTextureDatas(terrain, (Texture2D)fromObj, (Texture2D)toObj);\n                }\n\n                if (fromObj is GameObject go)\n                {\n                    TreePrototype[] arr2 = terrain.treePrototypes;\n                    for (var i = 0; i < arr2.Length; i++)\n                    {\n                        if (arr2[i].prefab != go) continue;\n                        found++;\n                        arr2[i].prefab = (GameObject)toObj;\n                    }\n\n                    terrain.treePrototypes = arr2;\n                }\n\n                // EditorUtility.SetDirty(terrain);\n                // AssetDatabase.SaveAssets();\n                // AssetFinderUnity.UnloadUnusedAssets();\n                return found > 0;\n            }\n\n            AssetFinderLOG.LogWarning(\"Something wrong, should never be here - Ignored <\" + m_assetPath +\n                \"> : not a readable type, can not replace ! \" + type);\n            return false;\n        }\n\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAsset.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c543b7730e7086043a9e90ab6713e909\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAutoRefreshMode.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    public enum AssetFinderAutoRefreshMode\n    {\n        On, // Auto refresh enabled\n        Off, // Auto refresh disabled by user\n        AutoOff // Auto refresh automatically disabled due to frequent changes\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderAutoRefreshMode.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fcfe60c37601b3e419b544b3cf969b50\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AssetSearch.cs",
    "content": "// this file has been deleted"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AssetSearch.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8e7f2fbc78d4980488c970632c6aaab2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AsyncProcessor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderCache\n    {\n        internal static void DelayCheck4Changes()\n        {\n            EditorApplication.update -= Check;\n            EditorApplication.update += Check;\n        }\n\n        private static void Check()\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable)\n            {\n                delayCounter = 100;\n                return;\n            }\n\n            if (Api == null) return;\n            if (delayCounter-- > 0) return;\n            \n            \n            EditorApplication.update -= Check;\n            Api.IncrementalRefresh();\n        }\n\n        internal void Check4Changes(bool force)\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable)\n            {\n                DelayCheck4Changes();\n                return;\n            }\n\n            ready = false;\n            ReadFromProject(force);\n\n            // AssetFinderLOG.Log($\"After ReadFromProject :: WorkCount: {workCount}, AssetMap: {AssetMap.Count}, AssetList: {AssetList.Count}\");\n            Check4Work();\n        }\n\n        internal void RefreshUsedByOnlyFromCache()\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable) return;\n            ready = false;\n            ReadFromCache();\n            workCount = 0;\n            if (queueLoadContent != null) queueLoadContent.Clear();\n            Check4Usage();\n        }\n\n        internal void IncrementalRefresh()\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating || AssetFinderSettingExt.disable)\n            {\n                DelayCheck4Changes();\n                return;\n            }\n            \n            ready = false;\n            workCount = 0;\n            if (queueLoadContent != null) queueLoadContent.Clear();\n            if (AssetMap == null)\n            {\n                Debug.LogWarning(\"Why should the AssetMap == null? The FR2 cache might be incompatible?\");\n                return;\n            }\n            \n            // CRITICAL FIX: First check for new assets that were added to the project\n            var paths = AssetDatabase.GetAllAssetPaths();\n            cacheStamp++;\n            \n            // Check for new assets\n            foreach (string p in paths)\n            {\n                bool isValid = AssetFinderUnity.StringStartsWith(p, \"Assets/\", \"Packages/\", \"Library/\", \"ProjectSettings/\");\n                if (!isValid) continue;\n                \n                string guid = AssetDatabase.AssetPathToGUID(p);\n                if (!AssetFinderAsset.IsValidGUID(guid)) continue;\n\n                if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset))\n                {\n                    // New asset detected - add it\n                    AddAsset(guid, false); // Don't force, let auto refresh logic decide\n                }\n                else\n                {\n                    // Mark existing asset so it won't be deleted\n                    asset.refreshStamp = cacheStamp;\n                }\n            }\n            \n            // Remove deleted assets\n            for (int i = AssetList.Count - 1; i >= 0; i--)\n            {\n                if (AssetList[i].refreshStamp != cacheStamp) RemoveAsset(AssetList[i]);\n            }\n            \n            // Only process dirty assets and assets that have never been scanned\n            foreach (var asset in AssetList) // only scan in AssetList\n            {\n                // Skip non-critical assets\n                if (!asset.IsCriticalAsset())\n                {\n                    if (asset.isDirty)\n                    {\n                        AssetFinderLOG.Log($\"[INVALID] non-critical asset is dirty???\\n\" +\n                                $\" asset: {asset.assetPath}: isCritical = {asset.IsCriticalAsset()} | isDirty = {asset.isDirty} | assetType: {asset.type}\");\n                    }\n                    continue;\n                }\n                \n                // Skip ignored assets - they shouldn't have their content read\n                if (asset.IsExcluded)\n                {\n                    AssetFinderLOG.Log($\"Skipping ignored asset: {asset.assetPath}\");\n                    continue;\n                }\n                \n                // Only process if asset is dirty or has never been scanned\n                if (asset.isDirty || !asset.hasBeenScanned)\n                {\n                    workCount++;\n                    queueLoadContent.Add(asset);\n                }\n            }\n            \n            // Clear the HasChanged flag since we're now processing the changes\n            HasChanged = false;\n            \n            AssetFinderLOG.Log($\"Incremental refresh: Processing {workCount} dirty/unscanned assets\");\n            Check4Work();\n        }\n\n        internal void Check4Usage()\n        {\n            currentState = ProcessingState.BuildingUsedBy;\n            \n            // CRITICAL FIX: Clear UsedByMap for ALL assets in AssetMap, not just AssetList\n            // This ensures that non-critical assets (like PNGs) get their stale references cleared\n            foreach (var kvp in AssetMap)\n            {\n                var item = kvp.Value;\n                if (item.IsMissing) continue;\n                AssetFinderUnity.Clear(ref item.UsedByMap);\n            }\n\n            foreach (var item in AssetList)\n            {\n                if (item.IsMissing) continue;\n                AsyncUsedBy(item);\n            }\n            workCount = 0;\n            ready = true;\n            currentState = ProcessingState.Idle;\n            HasChanged = false; // Clear dirty state when processing is complete\n            onReady?.Invoke();\n        }\n\n        internal void Check4Work()\n        {\n            if (workCount == 0)\n            {\n                Check4Usage();\n                return;\n            }\n\n            ready = false;\n            currentState = ProcessingState.ReadingContent;\n            EditorApplication.update -= AsyncProcess;\n            EditorApplication.update += AsyncProcess;\n            AssetFinderAsset.ClearLog();\n        }\n\n        internal void AsyncProcess()\n        {\n            if (this == null) return;\n            if (AssetFinderSettingExt.disable) return;\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating) return;\n            if (frameSkipped++ < 10 - 2 * priority) return;\n\n            frameSkipped = 0;\n            float t = Time.realtimeSinceStartup;\n\n            // AssetFinderLOG.Log(\"AsyncProcess: time=\" + Mathf.Round(t) + \" : progress = \" + progress*workCount + \"/\" + workCount + \" : isReady =\" + isReady + \" ::: queueLoadCount = \" + queueLoadContent.Count);\n\n            if (!AsyncWork(queueLoadContent, AsyncLoadContent, t)) return;\n            AssetFinderAsset.WriteTotalScanTime();\n            EditorUtility.SetDirty(this);\n            AssetDatabase.SaveAssets();\n\n            EditorApplication.update -= AsyncProcess;\n            if (HasPendingChanges())\n            {\n                AssetFinderLOG.Log(\"FR2: Detected changes during processing, restarting incremental refresh\");\n                IncrementalRefresh();\n                return;\n            }\n            \n            Check4Usage();\n        }\n\n        \n        private bool HasPendingChanges()\n        {\n            return AssetMap.Any(kvp => kvp.Value.isDirty && !queueLoadContent.Contains(kvp.Value));\n        }\n\n        internal bool AsyncWork<T>(List<T> arr, Action<int, T> action, float t)\n        {\n            const float FRAME_DURATION = 1f / 60f; // Cache as const to avoid division\n            float endTime = t + FRAME_DURATION; // Calculate end time once\n\n            int c = arr.Count;\n            while (c-- > 0)\n            {\n                T last = arr[c];\n                arr.RemoveAt(c);\n                action(c, last);\n\n                // Check time less frequently to reduce overhead\n                if (Time.realtimeSinceStartup >= endTime) return false;\n            }\n\n            if (GC_CountDown-- <= 0) // GC every 5 frames\n            {\n                GC.Collect(2, GCCollectionMode.Forced, true, true);\n                GC_CountDown = 5;\n            }\n\n            return c <= 0;\n        }\n\n        internal void AsyncLoadContent(int idx, AssetFinderAsset asset)\n        {\n            // Update the current asset name\n            currentAssetName = asset.assetPath;\n\n            if (asset.fileInfoDirty) asset.LoadFileInfo();\n            if (asset.fileContentDirty) asset.LoadContentFast();\n        }\n\n        internal void AsyncUsedBy(AssetFinderAsset asset)\n        {\n            if (AssetMap == null) Check4Changes(false);\n\n            if (asset.IsFolder) return;\n\n            // AssetFinderLOG.Log(\"Async UsedBy: \" + asset.assetPath);\n\n            foreach (KeyValuePair<string, HashSet<long>> item in asset.UseGUIDs)\n            {\n                if (!AssetMap.TryGetValue(item.Key, out AssetFinderAsset tAsset)) continue;\n                if (tAsset == null || tAsset.UsedByMap == null) continue;\n\n                if (!tAsset.UsedByMap.ContainsKey(asset.guid)) tAsset.AddUsedBy(asset.guid, asset);\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.AsyncProcessor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6b401fe2e5dd2e740bfc479d22492019\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Constants.cs",
    "content": "using System.Collections.Generic;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderCache\n    {\n        internal const string DEFAULT_CACHE_PATH = \"Assets/_Sunflower/Editor/FinderCache/AssetFinderCache.asset\";\n        internal const string CACHE_VERSION = \"2.6.4\";\n\n        internal static int cacheStamp;\n        internal static System.Action onReady;\n\n        internal static bool _triedToLoadCache;\n        internal static AssetFinderCache _cache;\n\n        internal static string _cacheGUID;\n        internal static bool _cacheJustCreated;\n        internal static string _cachePath;\n        public static readonly int priority = 5;\n\n        private static readonly HashSet<string> SPECIAL_USE_ASSETS = new HashSet<string>\n        {\n            \"Assets/link.xml\", // this file used to control build/link process do not remove\n            \"Assets/csc.rsp\",\n            \"Assets/mcs.rsp\",\n            \"Assets/GoogleService-Info.plist\",\n            \"Assets/google-services.json\"\n        };\n\n        private static readonly HashSet<string> SPECIAL_EXTENSIONS = new HashSet<string>\n        {\n            \".asmdef\",\n            \".cginc\",\n            \".cs\",\n            \".dll\",\n            \".mdb\",\n            \".pdb\",\n            \".rsp\",\n            \".md\",\n            \".winmd\",\n            \".xml\",\n            \".XML\",\n            \".tsv\",\n            \".csv\",\n            \".json\",\n            \".pdf\",\n            \".txt\",\n            \".giparams\",\n            \".wlt\",\n            \".preset\",\n            \".exr\",\n            \".aar\",\n            \".srcaar\",\n            \".pom\",\n            \".bin\",\n            \".html\",\n            \".chm\",\n            \".data\",\n            \".jsp\",\n            \".unitypackage\"\n        };\n\n        [System.NonSerialized] internal static int delayCounter;\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Constants.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6c55ca682f1f6844b8cd730021311b53\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Lifecycle.cs",
    "content": "using System;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\nusing System.Linq;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n\n    internal partial class AssetFinderCache\n    {\n        public static bool CheckSameVersion()\n        {\n            if (_cache == null) return false;\n            return _cache._curCacheVersion == CACHE_VERSION;\n        }\n\n        public void MarkChanged()\n        {\n            HasChanged = true;\n        }\n\n        private static void FoundCache()\n        {\n            _cachePath = AssetDatabase.GetAssetPath(_cache);\n            _cache.ReadFromCache();\n\n            _cacheGUID = AssetDatabase.AssetPathToGUID(_cachePath);\n\n            if (AssetFinderSettingExt.isAutoRefreshEnabled || _cacheJustCreated)\n            {\n                if (_cacheJustCreated) _cache.Check4Changes(true);\n                else _cache.RefreshUsedByOnlyFromCache();\n            }\n            else\n            {\n                _cache.RefreshUsedByOnlyFromCache();\n            }\n            \n            // Reset flag after use\n            _cacheJustCreated = false;\n        }\n\n        private static bool RestoreCacheFromPath(string path, bool validateOnly, bool forceLoad)\n        {\n            if (string.IsNullOrEmpty(path)) return false;\n            if (!File.Exists(path)) return false;\n\n            _cache = AssetFinderUnity.LoadAssetAtPath<AssetFinderCache>(path);\n            if (_cache == null) return false;\n            if (validateOnly && !forceLoad) return true;\n\n            FoundCache();\n            return true;\n        }\n\n        private static void TryLoadCache()\n        {\n            _triedToLoadCache = true;\n\n            // Simple type-based search scoped to Assets/ only\n            var cacheAssets = AssetDatabase.FindAssets(\"t:AssetFinderCache\", new[] { \"Assets\" });\n            if (cacheAssets.Length > 0)\n                foreach (var guid in cacheAssets)\n                {\n                    var path = AssetDatabase.GUIDToAssetPath(guid);\n                    if (!string.IsNullOrEmpty(path) && RestoreCacheFromPath(path, true, true))\n                        return;\n                }\n        }\n\n        internal static void DeleteCache()\n        {\n            if (_cache == null) return;\n\n            try\n            {\n                _cache.AssetList.Clear();\n                _cache.AssetMap.Clear();\n                _cache.queueLoadContent.Clear();\n                _cache = null;\n                if (!string.IsNullOrEmpty(_cachePath)) AssetDatabase.DeleteAsset(_cachePath);\n            }\n            catch\n            {\n                // ignored\n            }\n\n            AssetDatabase.SaveAssets();\n            using (AssetFinderDev.NoLog)\n            {\n                AssetDatabase.Refresh();\n            }\n        }\n\n        internal static void CreateCache()\n        {\n            _cache = CreateInstance<AssetFinderCache>();\n            _cache._curCacheVersion = CACHE_VERSION;\n            var path = Application.dataPath + DEFAULT_CACHE_PATH\n                .Substring(0, DEFAULT_CACHE_PATH.LastIndexOf('/') + 1).Replace(\"Assets\", string.Empty);\n\n            if (!Directory.Exists(path)) Directory.CreateDirectory(path);\n\n            AssetDatabase.CreateAsset(_cache, DEFAULT_CACHE_PATH);\n            EditorUtility.SetDirty(_cache);\n\n            // Set force refresh flag for initial/recreated cache\n            _cacheJustCreated = true;\n            \n            FoundCache();\n\n            // Delay the scan by one frame so UI can update first\n            EditorApplication.delayCall -= DelayCheck4Changes;\n            EditorApplication.delayCall += DelayCheck4Changes;\n        }\n\n        private void OnEnable()\n        {\n            if (_cache == null) _cache = this;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Lifecycle.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f5c9fe5f4b20f53498fda1e06bf8ef0a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.ProjectManager.cs",
    "content": "using System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderCache\n    {\n        internal void ReadFromCache()\n        {\n            if (AssetFinderSettingExt.disable)\n            {\n                AssetFinderLOG.LogWarning(\"Something wrong??? FR2 is disabled!\");\n            }\n\n            if (AssetList == null) AssetList = new List<AssetFinderAsset>();\n\n            AssetFinderUnity.Clear(ref queueLoadContent);\n            AssetFinderUnity.Clear(ref AssetMap);\n\n            // Create a new filtered list for critical assets only\n            var filteredAssetList = new List<AssetFinderAsset>();\n\n            for (var i = 0; i < AssetList.Count; i++)\n            {\n                AssetFinderAsset item = AssetList[i];\n                item.state = AssetFinderAsset.AssetState.CACHE;\n\n                string path = AssetDatabase.GUIDToAssetPath(item.guid);\n                if (string.IsNullOrEmpty(path))\n                {\n                    item.type = AssetFinderAsset.AssetType.UNKNOWN; // to make sure if GUIDs being reused for a different kind of asset\n                    item.state = AssetFinderAsset.AssetState.MISSING;\n                    AssetMap.Add(item.guid, item);\n                    \n                    // Only keep critical assets in AssetList\n                    if (item.IsCriticalAsset())\n                    {\n                        filteredAssetList.Add(item);\n                    }\n                    continue;\n                }\n\n                if (AssetMap.ContainsKey(item.guid))\n                {\n\t\t\t\t\tAssetFinderLOG.LogWarning(\"Something wrong, cache found twice <\" + item.guid + \">\");\n                    continue;\n                }\n\n                AssetMap.Add(item.guid, item);\n                \n                // Only keep critical assets in AssetList\n                if (item.IsCriticalAsset())\n                {\n                    filteredAssetList.Add(item);\n                }\n            }\n            \n            // Replace AssetList with filtered list containing only critical assets\n            AssetList = filteredAssetList;\n        }\n\n        internal void ClearCacheCompletely()\n        {\n            // AssetFinderLOG.Log(\"=== ClearCacheCompletely START ===\");\n            // AssetFinderLOG.Log($\"Before Clear - AssetList: {AssetList?.Count ?? 0}, AssetMap: {AssetMap?.Count ?? 0}, queueLoadContent: {queueLoadContent?.Count ?? 0}\");\n            \n            // Clear all cache data structures\n            if (AssetList != null) AssetList.Clear();\n            else AssetList = new List<AssetFinderAsset>();\n            \n            if (AssetMap != null) AssetMap.Clear();\n            else AssetMap = new Dictionary<string, AssetFinderAsset>();\n            \n            if (queueLoadContent != null) queueLoadContent.Clear();\n            else queueLoadContent = new List<AssetFinderAsset>();\n            \n            // Reset state\n            ready = false;\n            workCount = 0;\n            cacheStamp = 0;\n            HasChanged = false;\n            currentState = ProcessingState.Idle;\n            \n            System.GC.Collect();\n        }\n\n        internal void ReadFromProject(bool force)\n        {\n            if (AssetMap == null || AssetMap.Count == 0) ReadFromCache();\n            foreach (string b in AssetFinderAsset.BUILT_IN_ASSETS)\n            {\n                if (AssetMap.ContainsKey(b)) continue;\n                var asset = new AssetFinderAsset(b);\n                AssetMap.Add(b, asset);\n                \n                // Only add built-in assets to AssetList if they are critical\n                if (asset.IsCriticalAsset())\n                {\n                    AssetList.Add(asset);\n                }\n            }\n\n            string[] paths = AssetDatabase.GetAllAssetPaths();\n            cacheStamp++;\n            workCount = 0;\n            if (queueLoadContent != null) queueLoadContent.Clear();\n\n            // Check for new assets\n            int validPaths = 0;\n            int newAssets = 0;\n            int existingAssets = 0;\n            foreach (string p in paths)\n            {\n                bool isValid = AssetFinderUnity.StringStartsWith(p, \"Assets/\", \"Packages/\", \"Library/\", \"ProjectSettings/\");\n                if (!isValid)\n                {\n                    continue; // Skip invalid paths silently to avoid log spam\n                }\n                \n                validPaths++;\n                string guid = AssetDatabase.AssetPathToGUID(p);\n                if (!AssetFinderAsset.IsValidGUID(guid)) \n                {\n                    continue;\n                }\n\n                if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset))\n                {\n                    newAssets++;\n                    AddAsset(guid, force);\n                } else\n                {\n                    existingAssets++;\n                    asset.refreshStamp = cacheStamp; // mark this asset so it won't be deleted\n                    if (!asset.IsCriticalAsset()) continue; // not something we can handle\n                    if (!asset.isDirty && !force) continue;\n                    if (force) asset.MarkAsDirty(true, true);\n                    if (!asset.IsExcluded && (force || _cacheJustCreated || AssetFinderSettingExt.isAutoRefreshEnabled))\n                    {\n                        workCount++;\n                        queueLoadContent.Add(asset);    \n                    }\n                }\n            }\n\n            // Check for deleted assets\n            for (int i = AssetList.Count - 1; i >= 0; i--)\n            {\n                if (AssetList[i].refreshStamp != cacheStamp) RemoveAsset(AssetList[i]);\n            }\n        }\n\n        internal void RefreshAsset(string guid, bool force)\n        {\n            if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset)) return;\n            RefreshAsset(asset, force);\n        }\n\n        internal void RefreshSelection()\n        {\n            string[] list = AssetFinderUnity.Selection_AssetGUIDs;\n            for (var i = 0; i < list.Length; i++)\n            {\n                RefreshAsset(list[i], true);\n            }\n\n            Check4Work();\n        }\n\n        internal void RefreshAsset(AssetFinderAsset asset, bool force)\n        {\n            asset.MarkAsDirty(true, force);\n            \n            // If we're currently processing and this asset isn't already in the queue, add it\n            if (currentState != ProcessingState.Idle && !queueLoadContent.Contains(asset))\n            {\n                workCount++;\n                queueLoadContent.Add(asset);\n            }\n            \n            DelayCheck4Changes();\n        }\n\n        internal void AddAsset(string guid, bool force = false)\n        {\n            if (AssetMap.ContainsKey(guid))\n            {\n                AssetFinderLOG.LogWarning(\"guid already exist <\" + guid + \">\");\n                return;\n            }\n\n            var asset = new AssetFinderAsset(guid);\n            asset.LoadPathInfo();\n            asset.refreshStamp = cacheStamp;\n            AssetMap.Add(guid, asset);\n\n            // Do not load content for AssetFinderCache asset\n            if (guid == CacheGUID) return;\n\n            if (!asset.IsCriticalAsset()) return;\n\n            // Critical assets (even if ignored) should be added to AssetList\n            AssetList.Add(asset);\n            \n            // CRITICAL FIX: Always queue new assets for content loading when force=true\n            bool shouldQueue = !asset.IsExcluded && (force || _cacheJustCreated || AssetFinderSettingExt.isAutoRefreshEnabled || currentState != ProcessingState.Idle);\n                    // AssetFinderLOG.Log($\"AddAsset: {asset.assetPath} - shouldQueue: {shouldQueue} (IsExcluded: {asset.IsExcluded}, force: {force}, _cacheJustCreated: {_cacheJustCreated}, autoRefresh: {AssetFinderSettingExt.isAutoRefreshEnabled}, currentState: {currentState})\");\n            \n            if (shouldQueue)\n            {\n                workCount++;\n                queueLoadContent.Add(asset);\n                        // AssetFinderLOG.Log($\"QUEUED new asset for content loading: {asset.assetPath}\");\n            }\n            else\n            {\n                // When content loading is skipped, mark as ready but dirty for future scans\n                asset.MarkAsDirty(true, false);\n                        // AssetFinderLOG.Log($\"SKIPPED new asset: {asset.assetPath} - marked as dirty for future scan\");\n            }\n        }\n\n        internal void RemoveAsset(string guid)\n        {\n            if (!AssetMap.ContainsKey(guid)) return;\n\n            RemoveAsset(AssetMap[guid]);\n        }\n\n        internal void RemoveAsset(AssetFinderAsset asset)\n        {\n            AssetList.Remove(asset);\n\n            // Deleted Asset : still in the map but not in the AssetList\n            asset.state = AssetFinderAsset.AssetState.MISSING;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.ProjectManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 462f88bf52231f446ad48db4501584fa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Scanner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderCache\n    {\n        internal List<List<string>> ScanSimilar(Action IgnoreWhenScan, Action IgnoreFolderWhenScan)\n        {\n            if (AssetMap == null) Check4Changes(true);\n\n            var dict = new Dictionary<string, List<AssetFinderAsset>>();\n            foreach (KeyValuePair<string, AssetFinderAsset> item in AssetMap)\n            {\n                if (item.Value == null) continue;\n                if (item.Value.IsMissing || item.Value.IsFolder) continue;\n                if (item.Value.inPlugins) continue;\n                if (item.Value.inEditor) continue;\n                if (item.Value.IsExcluded) continue;\n                if (!item.Value.assetPath.StartsWith(\"Assets/\")) continue;\n                if (AssetFinderSetting.IsTypeExcluded(AssetFinderAssetGroupDrawer.GetIndex(item.Value.extension)))\n                {\n                    if (IgnoreWhenScan != null) IgnoreWhenScan();\n                    continue;\n                }\n\n                string hash = item.Value.fileInfoHash;\n                if (string.IsNullOrEmpty(hash))\n                {\n                    AssetFinderLOG.LogWarning(\"Hash can not be null! \");\n                    continue;\n                }\n\n                if (!dict.TryGetValue(hash, out List<AssetFinderAsset> list))\n                {\n                    list = new List<AssetFinderAsset>();\n                    dict.Add(hash, list);\n                }\n\n                list.Add(item.Value);\n            }\n\n            return dict.Values\n                .Where(item => item.Count > 1)\n                .OrderByDescending(item => item[0].fileSize)\n                .Select(item => item.Select(asset => asset.assetPath).ToList())\n                .ToList();\n        }\n\n        internal List<AssetFinderAsset> ScanUnused(bool recursive = true)\n        {\n            if (AssetMap == null) Check4Changes(false);\n\n            // Get Addressable assets\n            HashSet<string> addressable = AssetFinderAddressable.isOk ? AssetFinderAddressable.GetAddresses()\n                .SelectMany(item => item.Value.assetGUIDs.Union(item.Value.childGUIDs))\n                .ToHashSet() : new HashSet<string>();\n\n            var result = new List<AssetFinderAsset>();\n            var unusedAssets = new HashSet<string>();\n            \n            // First pass: find directly unused assets (level 1)\n            foreach (KeyValuePair<string, AssetFinderAsset> item in AssetMap)\n            {\n                AssetFinderAsset v = item.Value;\n                if (v.IsMissing || v.inEditor || v.IsScript || v.inResources || v.inPlugins || v.inStreamingAsset || v.IsFolder) continue;\n\n                if (!v.assetPath.StartsWith(\"Assets/\")) continue; // ignore built-in / packages assets\n                if (v.forcedIncludedInBuild) continue; // ignore assets that are forced to be included in build\n                if (v.assetName == \"LICENSE\") continue; // ignore license files\n\n                // --- Ignore assets in ignored folders or exact ignored paths ---\n                bool isIgnored = AssetFinderSetting.IgnoreAsset.Any(ignore =>\n                    v.assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) ||\n                    (v.assetPath.StartsWith(ignore + \"/\", StringComparison.OrdinalIgnoreCase))\n                );\n                if (isIgnored) continue;\n\n                // --- Ignore assets with unknown or no extension ---\n                string ext = System.IO.Path.GetExtension(v.assetPath);\n                Type assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(v.assetPath);\n                if (string.IsNullOrEmpty(ext) || assetType == typeof(DefaultAsset))\n                {\n                    continue;\n                }\n\n                if (SPECIAL_USE_ASSETS.Contains(v.assetPath)) continue; // ignore assets with special use (can not remove)\n                if (SPECIAL_EXTENSIONS.Contains(v.extension)) continue;\n\n                if (v.type == AssetFinderAsset.AssetType.DLL) continue;\n                if (v.type == AssetFinderAsset.AssetType.SCRIPT) continue;\n                if (v.type == AssetFinderAsset.AssetType.UNKNOWN) continue;\n                if (addressable.Contains(v.guid)) continue;\n\n                // special handler for .spriteatlas\n                if (v.extension == \".spriteatlas\")\n                {\n                    var isInUsed = false;\n                    List<string> allSprites = v.UseGUIDs.Keys.ToList();\n                    foreach (string spriteGUID in allSprites)\n                    {\n                        AssetFinderAsset asset = Api.Get(spriteGUID);\n                        if (asset.UsedByMap.Count <= 1) continue; // only use by this atlas\n\n                        isInUsed = true;\n                        break; // this one is used by other assets\n                    }\n\n                    if (isInUsed) continue;\n                }\n\n                if (v.IsExcluded)\n                {\n                    // Debug.Log($\"Excluded: {v.assetPath}\");\n                    continue;\n                }\n\n                if (!string.IsNullOrEmpty(v.AtlasName)) continue;\n                if (!string.IsNullOrEmpty(v.AssetBundleName)) continue;\n                if (!string.IsNullOrEmpty(v.AddressableName)) continue;\n\n                if (v.UsedByMap.Count == 0) //&& !AssetFinderAsset.IGNORE_UNUSED_GUIDS.Contains(v.guid)\n                {\n                    result.Add(v);\n                    unusedAssets.Add(v.guid);\n                }\n            }\n            \n            // If not recursive, return the level 1 results\n            if (!recursive)\n            {\n                result.Sort((item1, item2) => item1.extension == item2.extension\n                    ? string.Compare(item1.assetPath, item2.assetPath, StringComparison.Ordinal)\n                    : string.Compare(item1.extension, item2.extension, StringComparison.Ordinal));\n                    \n                return result;\n            }\n            \n            // Recursive scan for higher level unused assets\n            bool foundNewUnused = true;\n            while (foundNewUnused)\n            {\n                foundNewUnused = false;\n                var newUnusedAssets = new HashSet<string>();\n                \n                foreach (KeyValuePair<string, AssetFinderAsset> item in AssetMap)\n                {\n                    AssetFinderAsset v = item.Value;\n                    \n                    // Skip if already in result or doesn't meet basic criteria\n                    if (unusedAssets.Contains(v.guid)) continue;\n                    if (v.IsMissing || v.inEditor || v.IsScript || v.inResources || v.inPlugins || v.inStreamingAsset || v.IsFolder) continue;\n                    if (!v.assetPath.StartsWith(\"Assets/\")) continue;\n                    if (v.forcedIncludedInBuild) continue;\n                    if (v.assetName == \"LICENSE\") continue;\n                    // --- Ignore assets in ignored folders or exact ignored paths ---\n                    bool isIgnored = AssetFinderSetting.IgnoreAsset.Any(ignore =>\n                        v.assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) ||\n                        (v.assetPath.StartsWith(ignore + \"/\", StringComparison.OrdinalIgnoreCase))\n                    );\n                    if (isIgnored) continue;\n                    // --- Ignore assets with unknown or no extension ---\n                    string ext = System.IO.Path.GetExtension(v.assetPath);\n                    Type assetType = UnityEditor.AssetDatabase.GetMainAssetTypeAtPath(v.assetPath);\n                    if (string.IsNullOrEmpty(ext) || assetType == typeof(DefaultAsset))\n                    {\n                        continue;\n                    }\n                    if (SPECIAL_USE_ASSETS.Contains(v.assetPath)) continue;\n                    if (SPECIAL_EXTENSIONS.Contains(v.extension)) continue;\n                    if (v.type == AssetFinderAsset.AssetType.DLL) continue;\n                    if (v.type == AssetFinderAsset.AssetType.SCRIPT) continue;\n                    if (v.type == AssetFinderAsset.AssetType.UNKNOWN) continue;\n                    if (addressable.Contains(v.guid)) continue;\n                    if (v.IsExcluded) continue;\n                    if (!string.IsNullOrEmpty(v.AtlasName)) continue;\n                    if (!string.IsNullOrEmpty(v.AssetBundleName)) continue;\n                    if (!string.IsNullOrEmpty(v.AddressableName)) continue;\n                    // Check if this asset is only used by already identified unused assets\n                    if (v.UsedByMap.Count > 0)\n                    {\n                        bool onlyUsedByUnusedAssets = true;\n                        foreach (var usedBy in v.UsedByMap)\n                        {\n                            if (!unusedAssets.Contains(usedBy.Key))\n                            {\n                                onlyUsedByUnusedAssets = false;\n                                break;\n                            }\n                        }\n                        \n                        if (onlyUsedByUnusedAssets)\n                        {\n                            result.Add(v);\n                            newUnusedAssets.Add(v.guid);\n                            foundNewUnused = true;\n                        }\n                    }\n                }\n                \n                // Add newly found unused assets to the master list\n                unusedAssets.UnionWith(newUnusedAssets);\n            }\n\n            result.Sort((item1, item2) => item1.extension == item2.extension\n                ? string.Compare(item1.assetPath, item2.assetPath, StringComparison.Ordinal)\n                : string.Compare(item1.extension, item2.extension, StringComparison.Ordinal));\n\n            return result;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Scanner.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 294f715733c2fbf41b655b25454bf807\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Search.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderCache\n    {\n        internal static List<string> FindUsage(string[] listGUIDs)\n        {\n            if (!isReady) return null;\n\n            List<AssetFinderAsset> refs = Api.FindAssets(listGUIDs, true);\n\n            for (var i = 0; i < refs.Count; i++)\n            {\n                List<AssetFinderAsset> tmp = AssetFinderAsset.FindUsage(refs[i]);\n\n                for (var j = 0; j < tmp.Count; j++)\n                {\n                    AssetFinderAsset itm = tmp[j];\n                    if (refs.Contains(itm)) continue;\n\n                    refs.Add(itm);\n                }\n            }\n\n            return refs.Select(item => item.guid).ToList();\n        }\n\n        internal AssetFinderAsset Get(string guid, bool autoNew = false)\n        {\n            if (autoNew && !AssetMap.ContainsKey(guid)) AddAsset(guid);\n            return AssetMap.GetValueOrDefault(guid);\n        }\n\n        internal List<AssetFinderAsset> FindAssetsOfType(AssetFinderAsset.AssetType type)\n        {\n            var result = new List<AssetFinderAsset>();\n            foreach (KeyValuePair<string, AssetFinderAsset> item in AssetMap)\n            {\n                if (item.Value.type != type) continue;\n\n                result.Add(item.Value);\n            }\n\n            return result;\n        }\n\n        internal AssetFinderAsset FindAsset(string guid, string fileId)\n        {\n            if (AssetMap == null) Check4Changes(false);\n            if (!isReady)\n            {\n\t\t\t    AssetFinderLOG.LogWarning(\"Cache not ready !\");\n                return null;\n            }\n\n            if (string.IsNullOrEmpty(guid)) return null;\n\n            //for (var i = 0; i < guids.Length; i++)\n            {\n                //string guid = guids[i];\n                if (!AssetMap.TryGetValue(guid, out AssetFinderAsset asset)) return null;\n\n                if (asset.IsMissing) return null;\n\n                if (asset.IsFolder) return null;\n                return asset;\n            }\n        }\n\n        internal List<AssetFinderAsset> FindAssets(string[] guids, bool scanFolder)\n        {\n            if (AssetMap == null) Check4Changes(false);\n\n            var result = new List<AssetFinderAsset>();\n\n            if (!isReady)\n            {\n\t\t\t    AssetFinderLOG.LogWarning(\"Cache not ready !\");\n                return result;\n            }\n\n            var folderList = new List<AssetFinderAsset>();\n\n            if (guids.Length == 0) return result;\n\n            for (var i = 0; i < guids.Length; i++)\n            {\n                string guid = guids[i];\n                AssetFinderAsset asset;\n                if (!AssetMap.TryGetValue(guid, out asset)) continue;\n\n                if (asset.IsMissing) continue;\n\n                if (asset.IsFolder)\n                {\n                    if (!folderList.Contains(asset)) folderList.Add(asset);\n                } else\n                {\n                    result.Add(asset);\n                }\n            }\n\n            if (!scanFolder || folderList.Count == 0) return result;\n\n            int count = folderList.Count;\n            for (var i = 0; i < count; i++)\n            {\n                AssetFinderAsset item = folderList[i];\n\n                // for (var j = 0; j < item.UseGUIDs.Count; j++)\n                // {\n                //     AssetFinderAsset a;\n                //     if (!AssetMap.TryGetValue(item.UseGUIDs[j], out a)) continue;\n                foreach (KeyValuePair<string, HashSet<long>> useM in item.UseGUIDs)\n                {\n                    AssetFinderAsset a;\n                    if (!AssetMap.TryGetValue(useM.Key, out a)) continue;\n\n                    if (a.IsMissing) continue;\n\n                    if (a.IsFolder)\n                    {\n                        if (!folderList.Contains(a))\n                        {\n                            folderList.Add(a);\n                            count++;\n                        }\n                    } else\n                    {\n                        result.Add(a);\n                    }\n                }\n            }\n\n            return result;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.Search.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 96e6f3d54f320f74cbcb5ebb0e8f987e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.cs",
    "content": "//#define AssetFinderDEBUG\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderCache : ScriptableObject\n    {\n\n        [SerializeField] private bool _autoRefresh;\n        [SerializeField] private string _curCacheVersion;\n\n        [SerializeField] public List<AssetFinderAsset> AssetList;\n        [SerializeField] internal AssetFinderSetting setting = new AssetFinderSetting();\n\n        // ----------------------------------- INSTANCE -------------------------------------\n\n        [SerializeField] public int timeStamp;\n        [NonSerialized] internal Dictionary<string, AssetFinderAsset> AssetMap;\n\n        // Track the current asset being processed\n        [NonSerialized] internal string currentAssetName;\n\n        private int frameSkipped;\n\n        internal int GC_CountDown = 5;\n        [NonSerialized] internal List<AssetFinderAsset> queueLoadContent;\n\n        internal bool ready;\n        [NonSerialized] internal int workCount;\n        [NonSerialized] internal ProcessingState currentState = ProcessingState.Idle;\n\n        internal static string CacheGUID\n        {\n            get\n            {\n                if (!string.IsNullOrEmpty(_cacheGUID)) return _cacheGUID;\n\n                if (_cache != null)\n                {\n                    _cachePath = AssetDatabase.GetAssetPath(_cache);\n                    _cacheGUID = AssetDatabase.AssetPathToGUID(_cachePath);\n                    return _cacheGUID;\n                }\n\n                return null;\n            }\n        }\n\n        internal static string CachePath\n        {\n            get\n            {\n                if (!string.IsNullOrEmpty(_cachePath)) return _cachePath;\n\n                if (_cache != null)\n                {\n                    _cachePath = AssetDatabase.GetAssetPath(_cache);\n                    return _cachePath;\n                }\n\n                return null;\n            }\n        }\n\n        [SerializeField] private bool _hasChanged;\n        public bool HasChanged \n        { \n            get => _hasChanged; \n            private set => _hasChanged = value; \n        }\n        \n        internal static bool hasChanges => Api != null && Api.workCount > 0;\n\n        public static void Reload()\n        {\n            DelayCheck4Changes();\n        }\n        \n        internal static AssetFinderCache Api\n        {\n            get\n            {\n                if (_cache != null) return _cache;\n                if (!_triedToLoadCache) TryLoadCache();\n                return _cache;\n            }\n        }\n\n        internal static bool isReady\n        {\n            get\n            {\n                if (AssetFinderSettingExt.disable) return false;\n                if (!_triedToLoadCache) TryLoadCache();\n                return (_cache != null) && _cache.ready;\n            }\n        }\n\n        internal static bool hasCache\n        {\n            get\n            {\n                if (!_triedToLoadCache) TryLoadCache();\n\n                return _cache != null;\n            }\n        }\n\n        internal float progress\n        {\n            get\n            {\n                int n = workCount - queueLoadContent.Count;\n                return workCount == 0 ? 1 : n / (float)workCount;\n            }\n        }\n    }\n\n    \n    internal enum ProcessingState\n    {\n        Idle,           // Not processing anything\n        ReadingContent, // Currently reading asset content\n        BuildingUsedBy  // Currently building usedBy relationships\n    }\n    internal static class AssetFinderLOG\n    {\n        public static void Log(object message)\n        {\n#if AssetFinderDEBUG || AssetFinderDEV\n            UnityEngine.Debug.Log(message);\n#endif\n        }\n\n        public static void Log(object message, UnityEngine.Object context)\n        {\n#if AssetFinderDEBUG || AssetFinderDEV\n            UnityEngine.Debug.Log(message, context);\n#endif\n        }\n\n        public static void LogWarning(object message)\n        {\n#if AssetFinderDEBUG || AssetFinderDEV\n            UnityEngine.Debug.LogWarning(message);\n#endif\n        }\n\n        public static void LogWarning(object message, UnityEngine.Object context)\n        {\n#if AssetFinderDEBUG || AssetFinderDEV\n            UnityEngine.Debug.LogWarning(message, context);\n#endif\n        }\n\n        public static void LogError(object message)\n        {\n#if AssetFinderDEBUG || AssetFinderDEV\n            UnityEngine.Debug.LogError(message);\n#endif\n        }\n\n        public static void LogError(object message, UnityEngine.Object context)\n        {\n#if AssetFinderDEBUG || AssetFinderDEV\n            UnityEngine.Debug.LogError(message, context);\n#endif\n        }\n    }\n\n    [CustomEditor(typeof(AssetFinderCache))]\n    internal class AssetFinderCacheEditor : UnityEditor.Editor\n    {\n        private static string inspectGUID;\n        private static int index;\n\n        public override void OnInspectorGUI()\n        {\n            var c = (AssetFinderCache)target;\n\n            GUILayout.Label(\"Total : \" + c.AssetList.Count);\n\n            // AssetFinderCache.DrawPriorityGUI();\n\n            UnityObject s = Selection.activeObject;\n            if (s == null) return;\n\n            string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(s));\n\n            if (inspectGUID != guid)\n            {\n                inspectGUID = guid;\n                index = c.AssetList.FindIndex(item => item.guid == guid);\n            }\n\n            if (index != -1)\n            {\n                if (index >= c.AssetList.Count) index = 0;\n\n                serializedObject.Update();\n                SerializedProperty prop = serializedObject.FindProperty(\"AssetList\").GetArrayElementAtIndex(index);\n                prop.isExpanded = true;\n                EditorGUILayout.PropertyField(prop, true);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderCache.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 30361f5a1e2f6bf449882a4a0fb04e00\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderGitUtil.cs",
    "content": "using System.IO;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class AssetFinderGitUtil\n    {\n        private static string gitRootPath;\n\n        public static bool IsGitProject()\n        {\n            if (!string.IsNullOrEmpty(gitRootPath)) return true;\n\n            string currentPath = Application.dataPath;\n            DirectoryInfo dir = new DirectoryInfo(currentPath);\n\n            var maxDepth = 10;\n            while (dir != null && maxDepth > 0) // Prevent infinite loop\n            {\n                maxDepth--;\n                if (Directory.Exists(Path.Combine(dir.FullName, \".git\")))\n                {\n                    gitRootPath = dir.FullName;\n                    return true;\n                }\n                dir = dir.Parent;\n            }\n\n            return false;\n        }\n\n        public static bool CheckGitIgnoreContainsFR2Cache()\n        {\n            if (string.IsNullOrEmpty(gitRootPath)) IsGitProject();\n            if (string.IsNullOrEmpty(gitRootPath)) return false;\n\n            string gitIgnorePath = Path.Combine(gitRootPath, \".gitignore\");\n            if (!File.Exists(gitIgnorePath)) return false;\n\n            string[] lines = File.ReadAllLines(gitIgnorePath);\n            foreach (string line in lines)\n            {\n                string trimmedLine = line.Trim();\n                if (string.IsNullOrEmpty(trimmedLine) || trimmedLine.StartsWith(\"#\")) continue;\n                \n                if (trimmedLine == \"**/AssetFinderCache.asset*\" || trimmedLine == \"AssetFinderCache.asset*\" || trimmedLine == \"*AssetFinderCache.asset*\")\n                {\n                    return true;\n                }\n            }\n            \n            return false;\n        }\n\n        public static void AddFR2CacheToGitIgnore()\n        {\n            try\n            {\n                string content = File.Exists(\".gitignore\") ? File.ReadAllText(\".gitignore\") : \"\";\n                \n                // Make sure the file ends with a newline\n                if (!string.IsNullOrEmpty(content) && !content.EndsWith(\"\\n\"))\n                {\n                    content += \"\\n\";\n                }\n                \n                content += \"**/AssetFinderCache.asset*\\n\";\n                File.WriteAllText(\".gitignore\", content);\n            }\n            catch (System.Exception e)\n            {\n                AssetFinderLOG.LogError($\"Failed to update .gitignore: {e.Message}\");\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderGitUtil.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fdb05d77241c6fe4093af96a6787ef3a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderNavigationHistory.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderNavigationHistory\n    {\n        private readonly List<UnityObject[]> history = new List<UnityObject[]>();\n        private int currentIndex = -1;\n        private const int MAX_HISTORY_SIZE = 20;\n        private AssetFinderWindowAll window;\n        private bool isNavigating = false;\n        \n        public bool CanGoBack => currentIndex > 0 && GetValidHistoryCount() > 1;\n        public bool CanGoForward => currentIndex < history.Count - 1 && GetValidHistoryCount() > 1;\n        \n        public void SetWindow(AssetFinderWindowAll windowAll)\n        {\n            window = windowAll;\n        }\n        \n        public void RecordSelection(UnityObject[] selection)\n        {\n            if (selection == null || selection.Length == 0) return;\n            if (isNavigating) return;\n            \n            var validSelection = selection.Where(obj => obj != null).ToArray();\n            if (validSelection.Length == 0) return;\n            \n            if (currentIndex >= 0 && currentIndex < history.Count)\n            {\n                UnityObject[] current = CleanHistoryEntry(history[currentIndex]);\n                if (AreSelectionsEqual(current, validSelection)) return;\n            }\n            \n            if (currentIndex < history.Count - 1)\n            {\n                history.RemoveRange(currentIndex + 1, history.Count - currentIndex - 1);\n            }\n            \n            history.Add(validSelection.ToArray());\n            currentIndex = history.Count - 1;\n            \n            if (history.Count > MAX_HISTORY_SIZE)\n            {\n                history.RemoveAt(0);\n                currentIndex--;\n            }\n        }\n        \n        public bool GoBack()\n        {\n            if (!CanGoBack) return false;\n            \n            CleanInvalidHistoryEntries();\n            \n            if (currentIndex <= 0) return false;\n            \n            currentIndex--;\n            var validSelection = CleanHistoryEntry(history[currentIndex]);\n            \n            if (validSelection.Length == 0)\n            {\n                history.RemoveAt(currentIndex);\n                if (currentIndex >= history.Count) currentIndex = history.Count - 1;\n                return GoBack();\n            }\n            \n            isNavigating = true;\n            UpdateFR2SelectionDirectly(validSelection);\n            isNavigating = false;\n            return true;\n        }\n        \n        public bool GoForward()\n        {\n            if (!CanGoForward) return false;\n            \n            CleanInvalidHistoryEntries();\n            \n            if (currentIndex >= history.Count - 1) return false;\n            \n            currentIndex++;\n            var validSelection = CleanHistoryEntry(history[currentIndex]);\n            \n            if (validSelection.Length == 0)\n            {\n                history.RemoveAt(currentIndex);\n                currentIndex--;\n                return GoForward();\n            }\n            \n            isNavigating = true;\n            UpdateFR2SelectionDirectly(validSelection);\n            isNavigating = false;\n            return true;\n        }\n        \n        private void CleanInvalidHistoryEntries()\n        {\n            for (int i = history.Count - 1; i >= 0; i--)\n            {\n                var cleanedEntry = CleanHistoryEntry(history[i]);\n                if (cleanedEntry.Length == 0)\n                {\n                    history.RemoveAt(i);\n                    if (currentIndex >= i) currentIndex--;\n                }\n                else\n                {\n                    history[i] = cleanedEntry;\n                }\n            }\n            \n            if (currentIndex < 0 && history.Count > 0) currentIndex = 0;\n            if (currentIndex >= history.Count) currentIndex = history.Count - 1;\n        }\n        \n        private UnityObject[] CleanHistoryEntry(UnityObject[] entry)\n        {\n            return entry?.Where(obj => obj != null).ToArray() ?? new UnityObject[0];\n        }\n        \n        private int GetValidHistoryCount()\n        {\n            return history.Count(entry => CleanHistoryEntry(entry).Length > 0);\n        }\n        \n        private void UpdateFR2SelectionDirectly(UnityObject[] selection)\n        {\n            if (window == null) return;\n            \n            var validSelection = selection?.Where(obj => obj != null).ToArray() ?? new UnityObject[0];\n            \n            // For navigation history, we want to directly set both Unity and FR2 selection\n            // We bypass the smart lock mechanism entirely by setting FR2 selection directly\n            window.SetFR2Selection(validSelection);\n            Selection.objects = validSelection;\n        }\n        \n        private static bool AreSelectionsEqual(UnityObject[] a, UnityObject[] b)\n        {\n            if (a.Length != b.Length) return false;\n            \n            for (int i = 0; i < a.Length; i++)\n            {\n                if (a[i] != b[i]) return false;\n            }\n            \n            return true;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderNavigationHistory.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ac0493b90c0af8f4fb734aa7650864ac\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSelectionManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    /// <summary>\n    /// Unified Selection Manager for FindReference2\n    /// \n    /// This system replaces the fragmented selection logic found in multiple classes and provides:\n    /// \n    /// BENEFITS:\n    /// - Single source of truth for all selection state\n    /// - Automatic Unity version compatibility (2019.4+ vs 2021+)\n    /// - Separation of scene objects vs assets with proper typing\n    /// - Reduced GC pressure through efficient data structures\n    /// - Centralized Selection.selectionChanged monitoring\n    /// - Thread-safe singleton pattern\n    /// \n    /// ARCHITECTURE:\n    /// - AssetFinderSelectionManager: Main coordinator and event dispatcher\n    /// - AssetFinderSceneSelection: Handles GameObject/Component selection with int instanceIds\n    /// - AssetFinderAssetSelection: Handles asset selection with GUID/FileID pairs\n    /// \n    /// UNITY VERSION DIFFERENCES HANDLED:\n    /// - Unity 2018.1+: Uses AssetDatabase.TryGetGUIDAndLocalFileIdentifier\n    /// - Pre-2018.1: Uses reflection to access m_LocalIdentfierInFile property\n    /// \n    /// USAGE:\n    /// - Window classes subscribe to AssetFinderSelectionManager.SelectionChanged\n    /// - Access current selection via Instance.SceneSelection or Instance.AssetSelection\n    /// - All selection changes automatically propagate to subscribers\n    /// \n    /// MIGRATION:\n    /// - Replaces scattered Selection.objects calls\n    /// - Eliminates string-based instanceId storage\n    /// - Removes duplicated Unity version compatibility code\n    /// - Centralizes selection caching and frame-based optimization\n    /// </summary>\n    [InitializeOnLoad]\n    internal class AssetFinderSelectionManager\n    {\n        public static event System.Action SelectionChanged;\n        private static AssetFinderSelectionManager _instance;\n\n        // Static constructor - called automatically when Unity loads/recompiles\n        static AssetFinderSelectionManager()\n        {\n            // Initialize immediately when class is loaded\n            Initialize();\n        }\n\n        public static AssetFinderSelectionManager Instance\n        {\n            get\n            {\n                if (_instance != null) return _instance;\n                Initialize();\n                return _instance;\n            }\n        }\n\n        private AssetFinderSceneSelection sceneSelection;\n        private AssetFinderAssetSelection assetSelection;\n\n        // Cached Unity selection for comparison\n        private UnityObject[] cachedUnitySelection = Array.Empty<UnityObject>();\n        public AssetFinderSceneSelection SceneSelection => sceneSelection;\n        public AssetFinderAssetSelection AssetSelection => assetSelection;\n\n        public bool IsSelectingSceneObjects => sceneSelection?.Count > 0;\n        public bool IsSelectingAssets => assetSelection?.Count > 0;\n        public bool HasSelection => TotalCount > 0;\n        public int TotalCount => (sceneSelection?.Count ?? 0) + (assetSelection?.Count ?? 0);\n\n        private static void Initialize()\n        {\n            if (_instance != null)\n            {\n                Debug.LogWarning(\"AssetFinderSelectionManager already initialized - cleaning up first\");\n                Cleanup();\n            }\n\n            _instance = new AssetFinderSelectionManager();\n            _instance.InitializeInstance();\n\n            // Ensure cleanup happens on domain reload\n#if UNITY_2019_1_OR_NEWER\n            UnityEditor.AssemblyReloadEvents.beforeAssemblyReload -= Cleanup;\n            UnityEditor.AssemblyReloadEvents.beforeAssemblyReload += Cleanup;\n#endif\n        }\n\n        private void InitializeInstance()\n        {\n            sceneSelection = new AssetFinderSceneSelection();\n            assetSelection = new AssetFinderAssetSelection();\n\n            // Ensure we don't double-subscribe (idempotent)\n            Selection.selectionChanged -= OnUnitySelectionChanged;\n            Selection.selectionChanged += OnUnitySelectionChanged;\n\n            // Initialize with current Unity selection\n            RefreshFromUnitySelection();\n        }\n\n        public UnityObject[] GetUnitySelection()\n        {\n            return cachedUnitySelection ?? Array.Empty<UnityObject>();\n        }\n\n        private void RefreshFromUnitySelection()\n        {\n            var currentSelection = Selection.objects ?? Array.Empty<UnityObject>();\n            if (AreSelectionsEqual(cachedUnitySelection, currentSelection)) return;\n            cachedUnitySelection = currentSelection;\n            UpdateFR2Selection(currentSelection);\n            SelectionChanged?.Invoke();\n        }\n\n        private static bool AreSelectionsEqual(UnityObject[] selection1, UnityObject[] selection2)\n        {\n            if (selection1 == null && selection2 == null) return true;\n            if (selection1 == null || selection2 == null) return false;\n            if (selection1.Length != selection2.Length) return false;\n\n            // Order matters for selection comparison\n            for (int i = 0; i < selection1.Length; i++)\n            {\n                if (selection1[i] != selection2[i]) return false;\n            }\n\n            return true;\n        }\n\n        internal void UpdateFR2Selection(UnityObject[] newSelection)\n        {\n            sceneSelection.Clear();\n            assetSelection.Clear();\n\n            if (newSelection == null || newSelection.Length == 0) return;\n\n            foreach (var obj in newSelection)\n            {\n                if (obj == null) continue;\n\n                if (AssetDatabase.Contains(obj))\n                {\n                    assetSelection.AddAsset(obj);\n                }\n                else if (obj is GameObject gameObject)\n                {\n                    sceneSelection.AddGameObject(gameObject);\n                }\n                else if (obj is Component component && component.gameObject != null)\n                {\n                    sceneSelection.AddGameObject(component.gameObject);\n                }\n            }\n        }\n\n        private void OnUnitySelectionChanged()\n        {\n            // AssetFinderLOG.Log(\"OnUnitySelectionChanged()\");\n            RefreshFromUnitySelection();\n        }\n        \n        public static void Cleanup()\n        {\n            if (_instance == null) return;\n            Selection.selectionChanged -= _instance.OnUnitySelectionChanged;\n            _instance = null;\n        }\n\n        internal class AssetFinderSceneSelection\n        {\n            private readonly HashSet<int> instanceIds = new HashSet<int>();\n            private readonly Dictionary<int, GameObject> gameObjects = new Dictionary<int, GameObject>();\n\n            // Cached array - updated only when collection changes\n            private GameObject[] cachedGameObjectArray = Array.Empty<GameObject>();\n            private bool arrayDirty = false;\n\n            public int Count => instanceIds.Count;\n            public IReadOnlyCollection<int> InstanceIds => instanceIds;\n            public IReadOnlyCollection<GameObject> GameObjects => gameObjects.Values;\n\n            public void AddGameObject(UnityObject obj)\n            {\n                if (obj == null) return;\n\n                GameObject go = obj as GameObject ?? (obj as Component)?.gameObject;\n                if (go == null) return;\n\n                int instanceId = go.GetInstanceID();\n                if (instanceIds.Add(instanceId))\n                {\n                    gameObjects[instanceId] = go;\n                    arrayDirty = true;\n                }\n            }\n\n            public void Remove(int instanceId)\n            {\n                if (instanceIds.Remove(instanceId))\n                {\n                    gameObjects.Remove(instanceId);\n                    arrayDirty = true;\n                }\n            }\n\n            public bool Contains(int instanceId)\n            {\n                return instanceIds.Contains(instanceId);\n            }\n\n            public bool Contains(GameObject go)\n            {\n                return go != null && instanceIds.Contains(go.GetInstanceID());\n            }\n\n            public void Clear()\n            {\n                instanceIds.Clear();\n                gameObjects.Clear();\n                arrayDirty = true;\n            }\n\n            public GameObject[] ToArray()\n            {\n                if (arrayDirty)\n                {\n                    cachedGameObjectArray = gameObjects.Values.Where(go => go != null).ToArray();\n                    arrayDirty = false;\n                }\n\n                return cachedGameObjectArray;\n            }\n        }\n\n        internal class AssetFinderAssetSelection\n        {\n            private readonly Dictionary<string, AssetEntry> assets = new Dictionary<string, AssetEntry>();\n\n            // Cached arrays - updated only when collection changes\n            private string[] cachedGuidsArray = Array.Empty<string>();\n            private bool guidArrayDirty = false;\n\n            public int Count => assets.Count;\n            public IReadOnlyCollection<string> AssetGuids => assets.Keys;\n            public IReadOnlyCollection<AssetEntry> AssetEntries => assets.Values;\n\n            public struct AssetEntry\n            {\n                public string guid;\n                public long fileId;\n                public string assetPath;\n\n                public AssetEntry(string guid, long fileId, string assetPath)\n                {\n                    this.guid = guid;\n                    this.fileId = fileId;\n                    this.assetPath = assetPath;\n                }\n            }\n\n            public void AddAsset(UnityObject obj)\n            {\n                if (obj == null) return;\n\n                string assetPath = AssetDatabase.GetAssetPath(obj);\n                if (string.IsNullOrEmpty(assetPath)) return;\n\n                string guid = AssetDatabase.AssetPathToGUID(assetPath);\n                if (string.IsNullOrEmpty(guid)) return;\n\n                long fileId = GetFileId(obj);\n\n                if (!assets.ContainsKey(guid))\n                {\n                    guidArrayDirty = true;\n                }\n\n                assets[guid] = new AssetEntry(guid, fileId, assetPath);\n            }\n\n            private static long GetFileId(UnityObject obj)\n            {\n#if UNITY_2018_1_OR_NEWER\n                if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out _, out long fileId))\n                {\n                    return fileId;\n                }\n#else\n            try\n            {\n                var serializedObject = new SerializedObject(obj);\n                var inspectorModeInfo = typeof(SerializedObject).GetProperty(\"inspectorMode\", \n                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);\n                inspectorModeInfo?.SetValue(serializedObject, InspectorMode.Debug, null);\n                \n                var localIdProp = serializedObject.FindProperty(\"m_LocalIdentfierInFile\");\n                if (localIdProp != null)\n                {\n                    long localId = localIdProp.longValue;\n                    if (localId <= 0) localId = localIdProp.intValue;\n                    return localId;\n                }\n            }\n            catch { }\n#endif\n                return -1;\n            }\n\n            public void Remove(string guid)\n            {\n                if (assets.Remove(guid))\n                {\n                    guidArrayDirty = true;\n                }\n            }\n\n            public bool Contains(string guid)\n            {\n                return assets.ContainsKey(guid);\n            }\n\n            public void Clear()\n            {\n                assets.Clear();\n                guidArrayDirty = true;\n            }\n\n            public string[] GetGuids()\n            {\n                if (guidArrayDirty)\n                {\n                    cachedGuidsArray = assets.Keys.ToArray();\n                    guidArrayDirty = false;\n                }\n\n                return cachedGuidsArray;\n            }\n\n            public AssetEntry? GetAssetEntry(string guid)\n            {\n                if (assets.TryGetValue(guid, out var entry)) return entry;\n                return null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSelectionManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 21a87406f1e91644592297a6bf1e285d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSettingExt.cs",
    "content": "using System;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [Serializable] internal class AssetFinderSettingExt\n    {\n        \n        public static AssetFinderAutoRefreshMode autoRefreshMode\n        {\n            get => inst._autoRefresh;\n            set\n            {\n                if (inst._autoRefresh == value) return;\n                inst._autoRefresh = value;\n                \n                EditorUtility.SetDirty(AssetFinderCache.Api);\n                EditorApplication.update -= DelaySave;\n                EditorApplication.update += DelaySave;\n            }\n        }\n\n        public static bool isAutoRefreshEnabled\n        {\n            get\n            {\n                if (EditorApplication.isPlayingOrWillChangePlaymode) return false;\n                return autoRefreshMode == AssetFinderAutoRefreshMode.On;\n            }\n        }\n        \n        public static bool disable\n        {\n            get => inst.internalDisabled;\n            set => inst.internalDisabled = value;\n        }\n        \n        public static bool hideToolsWarning\n        {\n            get => inst._hideToolsWarning;\n            set\n            {\n                if (inst._hideToolsWarning == value) return;\n                inst._hideToolsWarning = value;\n                \n                EditorUtility.SetDirty(AssetFinderCache.Api);\n                EditorApplication.update -= DelaySave;\n                EditorApplication.update += DelaySave;\n            }\n        }\n\n        public static bool isGitProject;\n        public static bool gitIgnoreAdded\n        {\n            get => inst._gitIgnoreAdded;\n            set\n            {\n                if (inst._gitIgnoreAdded == value) return;\n                inst._gitIgnoreAdded = value;\n                \n                EditorUtility.SetDirty(AssetFinderCache.Api);\n                EditorApplication.update -= DelaySave;\n                EditorApplication.update += DelaySave;\n            }\n        }\n        \n        public static bool hideGitIgnoreWarning\n        {\n            get => inst._hideGitIgnoreWarning;\n            set\n            {\n                if (inst._hideGitIgnoreWarning == value) return;\n                inst._hideGitIgnoreWarning = value;\n                \n                EditorUtility.SetDirty(AssetFinderCache.Api);\n                EditorApplication.update -= DelaySave;\n                EditorApplication.update += DelaySave;\n            }\n        }\n        \n        private const string path = \"Library/FR2/fr2.cfg\";\n        private static AssetFinderSettingExt inst;\n        \n        static AssetFinderSettingExt()\n        {\n            \n            inst = new AssetFinderSettingExt();\n            if (!File.Exists(path)) return;\n\n            try\n            {\n                string content = File.ReadAllText(path);\n                JsonUtility.FromJsonOverwrite(content, inst);\n            }\n            catch (Exception e)\n            {\n                AssetFinderLOG.LogWarning(e);\n            }\n        }\n\n        static void DelaySave()\n        {\n            EditorApplication.update -= DelaySave;\n            \n            try\n            {\n                Directory.CreateDirectory(\"Library/FR2/\");\n                File.WriteAllText(path, JsonUtility.ToJson(inst));\n            }\n            catch (Exception e)\n            {\n                AssetFinderLOG.LogWarning(e);\n            }\n        }\n        \n        [SerializeField] private bool _disableInPlayMode = true;\n        [SerializeField] private bool _disabled;\n        [SerializeField] private AssetFinderAutoRefreshMode _autoRefresh;\n        [SerializeField] private bool _hideToolsWarning;\n        [SerializeField] private bool _isGitProject;\n        [SerializeField] private bool _gitIgnoreAdded;\n        [SerializeField] private bool _hideGitIgnoreWarning;\n        \n        private bool internalDisabled\n        {\n            get => _disabled || (_disableInPlayMode && EditorApplication.isPlayingOrWillChangePlaymode);\n            set\n            {\n                ref bool disableRef = ref _disabled;\n                if (EditorApplication.isPlayingOrWillChangePlaymode) disableRef = ref _disableInPlayMode;\n                \n                if (disableRef == value) return;\n                disableRef = value;\n                \n                // disable at runtime: only disable `disableInPlayMode`\n                // enable at runtime: enable all\n                if (!value) _disabled = false;\n                EditorUtility.SetDirty(AssetFinderCache.Api);\n                EditorApplication.update -= DelaySave;\n                EditorApplication.update += DelaySave;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSettingExt.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 42a3a6faf827daa46aa8f448c8aec943\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSmartLock.cs",
    "content": "// #define AssetFinderDEBUG\n\n\nusing System;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderSmartLock\n    {\n        public enum PingLockState\n        {\n            None,\n            Scene,  // Ping/highlight action triggered from scene context\n            Asset   // Ping/highlight action triggered from asset context\n        }\n        \n        private PingLockState pingLockState = PingLockState.None;\n        public void SetPingLockState(PingLockState state)\n        {\n            pingLockState = state;\n            #if AssetFinderDEBUG\n            if (state != PingLockState.None)\n            {\n                AssetFinderLOG.Log($\"SmartLock: Set ping lock state to {state}\");\n            }\n            #endif\n        }\n        \n        public bool ConsumePingLockState()\n        {\n            bool hadPingLock = pingLockState != PingLockState.None;\n            if (hadPingLock)\n            {\n                // AssetFinderLOG.Log($\"SmartLock: Consuming ping lock state {pingLockState}\");\n                pingLockState = PingLockState.None;\n            }\n            return hadPingLock;\n        }\n        \n        public bool ShouldRefreshWithSmartLogic(EditorWindow window, UnityObject[] panelSelection = null)\n        {\n            if (!AssetFinderSelectionManager.Instance.HasSelection) return false;\n            if (ConsumePingLockState()) return false;\n            if (panelSelection == null || panelSelection.Length == 0) return true;\n            return window != EditorWindow.focusedWindow;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderSmartLock.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b83b815529ea4e343857b73a07eb868b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderWindowFocus.cs",
    "content": "\nusing System;\nusing UnityEditor;\nusing UnityEditor.Compilation;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [InitializeOnLoad]\n    public static class AssetFinderWindowFocus\n    {\n        public static event Action<EditorWindow> FocusedWindowChanged = delegate { };\n\n        public static string CurrentWindowType => EditorWindow.focusedWindow?.GetType().Name;\n        public static string PreviousWindowType { get; private set; }\n\n#if UNITY_6000_0_OR_NEWER\n        // ---------- Native implementation ----------\n        static AssetFinderWindowFocus()\n        {\n            EditorWindow.windowFocusChanged += Raise;\n            AssemblyReloadEvents.beforeAssemblyReload += Cleanup;\n        }\n\n        private static void Raise()\n        {\n            var current = EditorWindow.focusedWindow;\n            PreviousWindowType = _lastWindowType;\n            _lastWindowType = current?.GetType().Name;\n            if (current != null) FocusedWindowChanged(current);\n        }\n\n        private static void Cleanup() =>\n            EditorWindow.windowFocusChanged -= Raise;\n#elif UNITY_2023_1_OR_NEWER\n        // ---------- Legacy implementation for Unity 2023-2024 ----------\n        static AssetFinderWindowFocus()\n        {\n            EditorWindow.focusedWindowChanged += Raise;\n            AssemblyReloadEvents.beforeAssemblyReload += Cleanup;\n        }\n\n        private static void Raise()\n        {\n            var current = EditorWindow.focusedWindow;\n            PreviousWindowType = _lastWindowType;\n            _lastWindowType = current?.GetType().Name;\n            if (current != null) FocusedWindowChanged(current);\n        }\n\n        private static void Cleanup() =>\n            EditorWindow.focusedWindowChanged -= Raise;\n\n#else\n        // ---------- Fallback: poll each editor-tick ----------\n        private static EditorWindow _last;\n\n        static AssetFinderWindowFocus()\n        {\n            EditorApplication.update += Tick;\n            AssemblyReloadEvents.beforeAssemblyReload += Cleanup;\n        }\n\n        private static void Tick()\n        {\n            var current = EditorWindow.focusedWindow;\n            if (current == _last) return;\n            \n            PreviousWindowType = _lastWindowType;\n            _last = current;\n            _lastWindowType = current?.GetType().Name;\n            if (current != null) FocusedWindowChanged(current);\n        }\n\n        private static void Cleanup() =>\n            EditorApplication.update -= Tick;\n#endif\n\n        private static string _lastWindowType;\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core/AssetFinderWindowFocus.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cdd3a4fc755761c42b4a385842caecbc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Core.meta",
    "content": "fileFormatVersion: 2\nguid: fd43daf252014e319860d77e81a52db8\ntimeCreated: 1746365393"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDefine.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    internal static class AssetFinderDefine\n    {\n        internal static bool IsDebugModeEnabled()\n        {\n            string cscPath = GetCscFilePath();\n            return System.IO.File.Exists(cscPath) && HasDefine(System.IO.File.ReadAllText(cscPath), \"AssetFinderDEBUG\");\n        }\n        \n        internal static void ToggleDebugMode(bool enable)\n        {\n            string cscPath = GetCscFilePath();\n            string content = System.IO.File.Exists(cscPath) ? System.IO.File.ReadAllText(cscPath) : \"\";\n            \n            content = enable ? AddDefine(content, \"AssetFinderDEBUG\") : RemoveDefine(content, \"AssetFinderDEBUG\");\n            \n            if (!string.IsNullOrWhiteSpace(content))\n            {\n                System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(cscPath));\n                System.IO.File.WriteAllText(cscPath, content);\n            }\n            else if (System.IO.File.Exists(cscPath))\n            {\n                System.IO.File.Delete(cscPath);\n            }\n            \n            UnityEditor.AssetDatabase.Refresh();\n            UnityEngine.Debug.Log($\"FR2 Developer Mode {(enable ? \"enabled\" : \"disabled\")}. Unity will recompile.\");\n        }\n        \n        private static string GetCscFilePath()\n        {\n            return System.IO.Path.Combine(\"Assets\", \"csc.rsp\");\n        }\n        \n        internal static bool HasDefine(string content, string define)\n        {\n            if (string.IsNullOrWhiteSpace(content)) return false;\n            var defines = ReadDefines(content);\n            return defines.Contains(define);\n        }\n        \n        internal static string AddDefine(string content, string define)\n        {\n            var defines = ReadDefines(content);\n            if (!defines.Contains(define))\n            {\n                defines.Add(define);\n            }\n            return WriteDefines(defines);\n        }\n        \n        internal static string RemoveDefine(string content, string define)\n        {\n            var defines = ReadDefines(content);\n            defines.Remove(define);\n            return WriteDefines(defines);\n        }\n        \n        private static System.Collections.Generic.List<string> ReadDefines(string content)\n        {\n            var result = new System.Collections.Generic.List<string>();\n            if (string.IsNullOrWhiteSpace(content)) return result;\n            \n            string[] lines = content.Split('\\n');\n            foreach (string line in lines)\n            {\n                string trimmedLine = line.Trim();\n                if (trimmedLine.StartsWith(\"-define:\"))\n                {\n                    // Extract existing symbols from -define: (same logic as GDK)\n                    string definesString = trimmedLine.Substring(8); // Skip \"-define:\"\n                    if (!string.IsNullOrEmpty(definesString))\n                    {\n                        result.AddRange(definesString.Split(';'));\n                    }\n                }\n            }\n            return result;\n        }\n        \n        private static string WriteDefines(System.Collections.Generic.List<string> defines)\n        {\n            // Clean up empty/whitespace defines\n            var cleanDefines = new System.Collections.Generic.List<string>();\n            foreach (string define in defines)\n            {\n                string trimmed = define?.Trim();\n                if (!string.IsNullOrEmpty(trimmed))\n                {\n                    cleanDefines.Add(trimmed);\n                }\n            }\n            \n            // Write exactly like GDK does\n            return cleanDefines.Count > 0 ? $\"-define:{string.Join(\";\", cleanDefines)}\" : string.Empty;\n        }\n        \n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDefine.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6012e303bbe76174e8881b5cb101e950\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDev.cs",
    "content": "// #define AssetFinderDEV\nusing System;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public class AssetFinderDev\n    {\n        public static IDisposable NoLog => new NoLogScope();\n\n        private readonly struct NoLogScope : IDisposable\n        {\n#if AssetFinderDEV\n            internal NoLogScope(bool _) { }\n            public void Dispose() { }\n#else\n            private readonly bool _saved;\n            internal NoLogScope(bool _)\n            {\n                _saved = UnityEngine.Debug.unityLogger.logEnabled;\n                UnityEngine.Debug.unityLogger.logEnabled = false;\n            }\n            public void Dispose() => UnityEngine.Debug.unityLogger.logEnabled = _saved;\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderDev.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2e217d3aaf8ffd94d97abbbf9b0e9df5\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderReferenceValidator.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    #if AssetFinderDEV\n    /// <summary>\n    /// Comprehensive reference validation system comparing FR2 vs Unity's GetDependencies\n    /// </summary>\n    internal class AssetFinderReferenceValidator\n    {\n        private struct ValidationResult\n        {\n            public int totalAssets;\n            public int assetsWithDifferences;\n            public int missingInFR2;\n            public int extraInFR2;\n            public List<AssetDifference> differences;\n            public Dictionary<string, int> missingByExtension;\n            public Dictionary<string, int> extraByExtension;\n            public Dictionary<string, int> assetTypeIssues;\n        }\n\n        private struct AssetDifference\n        {\n            public string assetPath;\n            public string guid;\n            public string assetType;\n            public List<string> missingInFR2;   // In Unity but not in FR2\n            public List<string> extraInFR2;    // In FR2 but not in Unity\n            public string summary;\n        }\n\n        private readonly Dictionary<string, string[]> unityDependencyCache = new Dictionary<string, string[]>();\n        private readonly System.Text.StringBuilder reportBuilder = new System.Text.StringBuilder();\n\n        public void ValidateAllReferences(bool exportToFile = false)\n        {\n            var startTime = System.DateTime.Now;\n            var result = new ValidationResult\n            {\n                differences = new List<AssetDifference>(),\n                missingByExtension = new Dictionary<string, int>(),\n                extraByExtension = new Dictionary<string, int>(),\n                assetTypeIssues = new Dictionary<string, int>()\n            };\n\n            // Clear caches\n            unityDependencyCache.Clear();\n            reportBuilder.Clear();\n\n            // Get all critical assets from FR2 cache\n            var criticalAssets = AssetFinderCache.Api.AssetList\n                .Where(asset => asset != null && !asset.IsMissing && asset.IsCriticalAsset())\n                .ToList();\n\n            result.totalAssets = criticalAssets.Count;\n            AppendToReport($\"=== FR2 REFERENCE VALIDATION REPORT ===\");\n            AppendToReport($\"Generated: {System.DateTime.Now:yyyy-MM-dd HH:mm:ss}\");\n            AppendToReport($\"Total critical assets to analyze: {result.totalAssets}\");\n            AppendToReport(\"\");\n\n            AssetFinderLOG.Log($\"[AssetFinderVALIDATION] Analyzing {result.totalAssets} critical assets...\");\n\n            var processedCount = 0;\n            var lastProgressReport = 0;\n\n            foreach (var asset in criticalAssets)\n            {\n                processedCount++;\n                \n                // Progress reporting (every 10%)\n                var progressPercent = (processedCount * 100) / result.totalAssets;\n                if (progressPercent >= lastProgressReport + 10)\n                {\n                    lastProgressReport = progressPercent;\n                    AssetFinderLOG.Log($\"[AssetFinderVALIDATION] Progress: {progressPercent}% ({processedCount}/{result.totalAssets})\");\n                }\n\n                var difference = CompareAssetReferences(asset);\n                if (difference.missingInFR2.Count > 0 || difference.extraInFR2.Count > 0)\n                {\n                    result.differences.Add(difference);\n                    result.assetsWithDifferences++;\n                    result.missingInFR2 += difference.missingInFR2.Count;\n                    result.extraInFR2 += difference.extraInFR2.Count;\n\n                    // Track by extension and asset type\n                    string assetExt = System.IO.Path.GetExtension(asset.assetPath).ToLower();\n                    result.assetTypeIssues[assetExt] = result.assetTypeIssues.GetValueOrDefault(assetExt, 0) + 1;\n\n                    foreach (var missing in difference.missingInFR2)\n                    {\n                        string depPath = ExtractPathFromDependencyString(missing);\n                        string depExt = System.IO.Path.GetExtension(depPath).ToLower();\n                        result.missingByExtension[depExt] = result.missingByExtension.GetValueOrDefault(depExt, 0) + 1;\n                    }\n\n                    foreach (var extra in difference.extraInFR2)\n                    {\n                        string depPath = ExtractPathFromDependencyString(extra);\n                        string depExt = System.IO.Path.GetExtension(depPath).ToLower();\n                        result.extraByExtension[depExt] = result.extraByExtension.GetValueOrDefault(depExt, 0) + 1;\n                    }\n                }\n            }\n\n            var duration = System.DateTime.Now - startTime;\n            LogValidationResults(result, duration, exportToFile);\n        }\n\n        private AssetDifference CompareAssetReferences(AssetFinderAsset asset)\n        {\n            var difference = new AssetDifference\n            {\n                assetPath = asset.assetPath,\n                guid = asset.guid,\n                assetType = asset.type.ToString(),\n                missingInFR2 = new List<string>(),\n                extraInFR2 = new List<string>()\n            };\n\n            try\n            {\n                // Get Unity's dependencies (with caching)\n                string[] unityDeps;\n                if (!unityDependencyCache.TryGetValue(asset.assetPath, out unityDeps))\n                {\n                    unityDeps = AssetDatabase.GetDependencies(asset.assetPath, false); // Direct dependencies only\n                    unityDependencyCache[asset.assetPath] = unityDeps;\n                }\n\n                var unityGuids = new HashSet<string>();\n                foreach (string depPath in unityDeps)\n                {\n                    if (depPath == asset.assetPath) continue; // Skip self-reference\n                    string depGuid = AssetDatabase.AssetPathToGUID(depPath);\n                    if (!string.IsNullOrEmpty(depGuid))\n                    {\n                        unityGuids.Add(depGuid);\n                    }\n                }\n\n                // Get FR2's dependencies\n                var fr2Guids = new HashSet<string>();\n                if (asset.UseGUIDs != null)\n                {\n                    fr2Guids.UnionWith(asset.UseGUIDs.Keys);\n                }\n\n                // Find differences\n                foreach (string unityGuid in unityGuids)\n                {\n                    if (!fr2Guids.Contains(unityGuid))\n                    {\n                        string depPath = AssetDatabase.GUIDToAssetPath(unityGuid);\n                        difference.missingInFR2.Add($\"{unityGuid} ({depPath})\");\n                    }\n                }\n\n                foreach (string fr2Guid in fr2Guids)\n                {\n                    if (!unityGuids.Contains(fr2Guid))\n                    {\n                        string depPath = AssetDatabase.GUIDToAssetPath(fr2Guid);\n                        difference.extraInFR2.Add($\"{fr2Guid} ({depPath})\");\n                    }\n                }\n\n                // Create summary\n                if (difference.missingInFR2.Count > 0 || difference.extraInFR2.Count > 0)\n                {\n                    difference.summary = $\"Missing: {difference.missingInFR2.Count}, Extra: {difference.extraInFR2.Count}\";\n                }\n            }\n            catch (System.Exception e)\n            {\n                difference.summary = $\"Error during comparison: {e.Message}\";\n            }\n\n            return difference;\n        }\n\n        private void LogValidationResults(ValidationResult result, System.TimeSpan duration, bool exportToFile)\n        {\n            AppendToReport($\"Analysis completed in {duration.TotalSeconds:F2} seconds\");\n            AppendToReport($\"Assets with differences: {result.assetsWithDifferences}\");\n            AppendToReport($\"Total missing references in FR2: {result.missingInFR2}\");\n            AppendToReport($\"Total extra references in FR2: {result.extraInFR2}\");\n            AppendToReport(\"\");\n\n            if (result.assetsWithDifferences == 0)\n            {\n                AppendToReport(\"🎉 Perfect match! FR2 and Unity have identical reference detection.\");\n                AssetFinderLOG.Log(\"🎉 Perfect match! FR2 and Unity have identical reference detection.\");\n            }\n            else\n            {\n                float accuracy = ((result.totalAssets - result.assetsWithDifferences) * 100f / result.totalAssets);\n                AppendToReport($\"Accuracy: {accuracy:F1}%\");\n                AssetFinderLOG.Log($\"[AssetFinderVALIDATION] Accuracy: {accuracy:F1}%\");\n\n                GenerateDetailedReport(result);\n            }\n\n            if (exportToFile)\n            {\n                string filePath = System.IO.Path.Combine(Application.dataPath, \"../AssetFinderValidation_Report.txt\");\n                System.IO.File.WriteAllText(filePath, reportBuilder.ToString());\n                AssetFinderLOG.Log($\"[AssetFinderVALIDATION] Detailed report exported to: {filePath}\");\n            }\n            else\n            {\n                // Console output (limited)\n                AssetFinderLOG.Log(\"=== FR2 REFERENCE VALIDATION RESULTS ===\");\n                AssetFinderLOG.Log($\"Analysis completed in {duration.TotalSeconds:F2} seconds\");\n                AssetFinderLOG.Log($\"Total assets analyzed: {result.totalAssets}\");\n                AssetFinderLOG.Log($\"Assets with differences: {result.assetsWithDifferences}\");\n                if (result.assetsWithDifferences > 0)\n                {\n                    AssetFinderLOG.Log($\"Accuracy: {((result.totalAssets - result.assetsWithDifferences) * 100f / result.totalAssets):F1}%\");\n                    AssetFinderLOG.Log(\"Use 'Validate References (Export to File)' for detailed analysis.\");\n                }\n            }\n        }\n\n        private void GenerateDetailedReport(ValidationResult result)\n        {\n            AppendToReport(\"=== TOP PROBLEMATIC ASSET TYPES ===\");\n            foreach (var kvp in result.assetTypeIssues.OrderByDescending(x => x.Value).Take(10))\n            {\n                AppendToReport($\"{kvp.Key}: {kvp.Value} assets with differences\");\n            }\n            AppendToReport(\"\");\n\n            AppendToReport(\"=== MOST COMMONLY MISSED DEPENDENCY TYPES ===\");\n            foreach (var kvp in result.missingByExtension.OrderByDescending(x => x.Value).Take(10))\n            {\n                AppendToReport($\"{kvp.Key}: {kvp.Value} instances\");\n            }\n            AppendToReport(\"\");\n\n            AppendToReport(\"=== MOST COMMONLY OVER-DETECTED TYPES ===\");\n            foreach (var kvp in result.extraByExtension.OrderByDescending(x => x.Value).Take(10))\n            {\n                AppendToReport($\"{kvp.Key}: {kvp.Value} instances\");\n            }\n            AppendToReport(\"\");\n\n            AppendToReport(\"=== DETAILED DIFFERENCES ===\");\n            var maxDetailsToShow = Mathf.Min(50, result.differences.Count);\n            if (result.differences.Count > maxDetailsToShow)\n            {\n                AppendToReport($\"Showing first {maxDetailsToShow} differences (out of {result.differences.Count} total):\");\n            }\n\n            for (int i = 0; i < maxDetailsToShow; i++)\n            {\n                var diff = result.differences[i];\n                AppendToReport($\"\\n[{i + 1}] {diff.assetPath}\");\n                AppendToReport($\"    Type: {diff.assetType} | GUID: {diff.guid}\");\n                AppendToReport($\"    Summary: {diff.summary}\");\n\n                if (diff.missingInFR2.Count > 0)\n                {\n                    AppendToReport($\"    Missing in FR2 ({diff.missingInFR2.Count}):\");\n                    foreach (var missing in diff.missingInFR2.Take(5))\n                    {\n                        AppendToReport($\"      - {missing}\");\n                    }\n                    if (diff.missingInFR2.Count > 5)\n                    {\n                        AppendToReport($\"      ... and {diff.missingInFR2.Count - 5} more\");\n                    }\n                }\n\n                if (diff.extraInFR2.Count > 0)\n                {\n                    AppendToReport($\"    Extra in FR2 ({diff.extraInFR2.Count}):\");\n                    foreach (var extra in diff.extraInFR2.Take(5))\n                    {\n                        AppendToReport($\"      - {extra}\");\n                    }\n                    if (diff.extraInFR2.Count > 5)\n                    {\n                        AppendToReport($\"      ... and {diff.extraInFR2.Count - 5} more\");\n                    }\n                }\n            }\n        }\n\n        private void AppendToReport(string line)\n        {\n            reportBuilder.AppendLine(line);\n        }\n\n        private string ExtractPathFromDependencyString(string depString)\n        {\n            // Extract path from format \"guid (path)\"\n            int startParen = depString.IndexOf('(');\n            int endParen = depString.IndexOf(')', startParen);\n            if (startParen >= 0 && endParen > startParen)\n            {\n                return depString.Substring(startParen + 1, endParen - startParen - 1);\n            }\n            return depString;\n        }\n\n        private void AnalyzeValidationPatterns(List<AssetDifference> differences)\n        {\n            // This method is now integrated into GenerateDetailedReport\n        }\n    }\n    #endif\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderReferenceValidator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 95909f9cceec2c94d98b1f9a061b26d3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderWindowAll.Validator.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        public override void AddToCustomMenu(GenericMenu menu)\n        {\n#if AssetFinderDEV\n            menu.AddItem(new GUIContent(\"Refresh Cache\"), false, () => AssetFinderCache.Api.Check4Changes(true));\n            menu.AddItem(new GUIContent(\"Validate References vs Unity\"), false, ()=>ValidateReferencesVsUnity());\n            menu.AddItem(new GUIContent(\"Validate References (Export to File)\"), false, () => ValidateReferencesVsUnity(true));\n            menu.AddItem(new GUIContent(\"Debug Selected Assets\"), false, DebugSelectedAssets);\n#endif\n        }\n\n#if AssetFinderDEV\n        private void ValidateReferencesVsUnity(bool exportToFile = false)\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"[AssetFinderVALIDATION] Cache not ready. Please wait for cache to finish loading.\");\n                return;\n            }\n\n            if (exportToFile)\n            {\n                AssetFinderLOG.Log(\"[AssetFinderVALIDATION] Starting validation with file export...\");\n            }\n            else\n            {\n                AssetFinderLOG.Log(\"[AssetFinderVALIDATION] Starting comprehensive reference validation against Unity's GetDependencies...\");\n            }\n            \n            var validator = new AssetFinderReferenceValidator();\n            validator.ValidateAllReferences(exportToFile);\n        }\n\n        private void DebugSelectedAssets()\n        {\n            if (Selection.objects == null || Selection.objects.Length == 0)\n            {\n                AssetFinderLOG.LogWarning(\"[AssetFinderDEBUG] No objects selected for debugging\");\n                return;\n            }\n\n            foreach (var obj in Selection.objects)\n            {\n                string path = AssetDatabase.GetAssetPath(obj);\n                if (string.IsNullOrEmpty(path)) continue;\n\n                string guid = AssetDatabase.AssetPathToGUID(path);\n                Debug.Log($\"[AssetFinderDEBUG] === {obj.name} ({guid}) ===\");\n\n                if (!AssetFinderCache.isReady)\n                {\n                    AssetFinderLOG.LogWarning(\"[AssetFinderDEBUG] Cache not ready!\");\n                    continue;\n                }\n\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                if (asset == null)\n                {\n                    AssetFinderLOG.LogWarning(\"[AssetFinderDEBUG] Asset not found in cache!\");\n                    continue;\n                }\n\n                Debug.Log($\"Type: {asset.type} | Critical: {asset.IsCriticalAsset()} | Extension: {asset.extension}\");\n                AssetFinderLOG.Log($\"Uses: {asset.UseGUIDs?.Count ?? 0} | UsedBy: {asset.UsedByMap?.Count ?? 0}\");\n                Debug.Log($\"InAssetList: {AssetFinderCache.Api.AssetList?.Contains(asset) ?? false} | Dirty: {asset.isDirty}\");\n            }\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev/AssetFinderWindowAll.Validator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dd971677ed211ef41826f4ab2d3bb028\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Dev.meta",
    "content": "fileFormatVersion: 2\nguid: d6d7bf6fb14b44c697ed962d9ca4fac6\ntimeCreated: 1753192840"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAddressableDrawer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderAddressableDrawer : IRefDraw\n    {\n        private const string AUTO_DEPEND_TITLE = \"(Auto dependency)\";\n\n        private readonly Dictionary<AssetFinderAddressable.ASMStatus, string> AsmMessage = new Dictionary<AssetFinderAddressable.ASMStatus, string>\n        {\n            { AssetFinderAddressable.ASMStatus.None, \"-\" },\n            { AssetFinderAddressable.ASMStatus.AsmNotFound, \"Addressable Package not imported!\" },\n            { AssetFinderAddressable.ASMStatus.TypeNotFound, \"Addressable Classes not found (addressable library code changed?)!\" },\n            { AssetFinderAddressable.ASMStatus.FieldNotFound, \"Addressable Fields not found (addressable library code changed?)!\" },\n            { AssetFinderAddressable.ASMStatus.AsmOK, \"-\" }\n        };\n\n        internal readonly AssetFinderRefDrawer drawer;\n        internal readonly Dictionary<string, AssetFinderAddressable.AddressInfo> map = new Dictionary<string, AssetFinderAddressable.AddressInfo>();\n\n        private readonly Dictionary<AssetFinderAddressable.ProjectStatus, string> ProjectStatusMessage = new Dictionary<AssetFinderAddressable.ProjectStatus, string>\n        {\n            { AssetFinderAddressable.ProjectStatus.None, \"-\" },\n            { AssetFinderAddressable.ProjectStatus.NoSettings, \"No Addressables Settings found!\\nOpen [Window/Asset Management/Addressables/Groups] to create new Addressables Settings!\\n \\n\" },\n            { AssetFinderAddressable.ProjectStatus.NoGroup, \"No AssetBundle Group created!\" },\n            { AssetFinderAddressable.ProjectStatus.Ok, \"-\" }\n        };\n        private bool dirty;\n        internal List<string> groups;\n        internal float maxWidth;\n        internal Dictionary<string, AssetFinderRef> refs;\n\n        public AssetFinderAddressableDrawer(IWindow window, Func<AssetFinderRefDrawer.Sort> getSortMode, Func<AssetFinderRefDrawer.Mode> getGroupMode)\n        {\n            this.window = window;\n            drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = window,\n                getSortMode = getSortMode,\n                getGroupMode = getGroupMode,\n                showFullPath = false,\n                showFileSize = true,\n                showExtension = true,\n                showUsageType = false,\n                showAssetBundleName = false,\n                showAtlasName = false\n            })\n            {\n                messageNoRefs = \"No Addressable Asset\",\n                messageEmpty = \"No Addressable Asset\",\n                customGetGroup = GetGroup,\n\n                customDrawGroupLabel = DrawGroupLabel,\n                beforeItemDraw = BeforeDrawItem,\n                afterItemDraw = AfterDrawItem\n            };\n\n            dirty = true;\n            drawer.SetDirty();\n        }\n\n        public IWindow window { get; set; }\n\n\n        public int ElementCount()\n        {\n            return refs?.Count ?? 0;\n        }\n\n        public bool Draw(Rect rect)\n        {\n            if (dirty) RefreshView();\n            if (refs == null) return false;\n\n            rect.yMax -= 24f;\n            bool result = drawer.Draw(rect);\n\n            Rect btnRect = rect;\n            btnRect.xMin = btnRect.xMax - 24f;\n            btnRect.yMin = btnRect.yMax;\n            btnRect.height = 24f;\n\n            if (GUI.Button(btnRect, AssetFinderIcon.Refresh.image))\n            {\n                AssetFinderAddressable.Scan();\n                RefreshView();\n            }\n\n            return result;\n        }\n\n        public bool DrawLayout()\n        {\n            if (dirty) RefreshView();\n            return drawer.DrawLayout();\n        }\n\n        private string GetGroup(AssetFinderRef rf)\n        {\n            return rf.group;\n        }\n\n        private void DrawGroupLabel(Rect r, string label, int childCount)\n        {\n            Color c = GUI.contentColor;\n            if (label == AUTO_DEPEND_TITLE)\n            {\n                Color c1 = c;\n                c1.a = 0.5f;\n                GUI.contentColor = c1;\n            }\n\n            GUI.Label(r, AssetFinderGUIContent.FromString(label), EditorStyles.boldLabel);\n            GUI.contentColor = c;\n        }\n\n        private void BeforeDrawItem(Rect r, AssetFinderRef rf)\n        {\n            string guid = rf.asset.guid;\n            if (map.TryGetValue(guid, out AssetFinderAddressable.AddressInfo address)) return;\n\n            Color c = GUI.contentColor;\n            c.a = 0.35f;\n            GUI.contentColor = c;\n        }\n\n        private void AfterDrawItem(Rect r, AssetFinderRef rf)\n        {\n            string guid = rf.asset.guid;\n            if (!map.TryGetValue(guid, out AssetFinderAddressable.AddressInfo address))\n            {\n                Color c2 = GUI.contentColor;\n                c2.a = 1f;\n                GUI.contentColor = c2;\n                return;\n            }\n\n            Color c = GUI.contentColor;\n            Color c1 = c;\n            c1.a = 0.5f;\n\n            GUI.contentColor = c1;\n            {\n                r.xMin = r.xMax - maxWidth;\n                GUI.Label(r, AssetFinderGUIContent.FromString(address.address), EditorStyles.miniLabel);\n            }\n            GUI.contentColor = c;\n\n        }\n\n        public void SetDirty()\n        {\n            dirty = true;\n            drawer.SetDirty();\n        }\n\n\n\n        public void RefreshView()\n        {\n            if (refs == null) refs = new Dictionary<string, AssetFinderRef>();\n            refs.Clear();\n\n            Dictionary<string, AssetFinderAddressable.AddressInfo> addresses = AssetFinderAddressable.GetAddresses();\n            if (AssetFinderAddressable.asmStatus != AssetFinderAddressable.ASMStatus.AsmOK)\n            {\n                drawer.messageNoRefs = AsmMessage[AssetFinderAddressable.asmStatus];\n            } else if (AssetFinderAddressable.projectStatus != AssetFinderAddressable.ProjectStatus.Ok)\n            {\n                drawer.messageNoRefs = ProjectStatusMessage[AssetFinderAddressable.projectStatus];\n            }\n            drawer.messageEmpty = drawer.messageNoRefs;\n\n            if (addresses == null) addresses = new Dictionary<string, AssetFinderAddressable.AddressInfo>();\n            groups = addresses.Keys.ToList();\n            map.Clear();\n\n            if (addresses.Count > 0)\n            {\n                var maxLengthGroup = string.Empty;\n                foreach (KeyValuePair<string, AssetFinderAddressable.AddressInfo> kvp in addresses)\n                {\n                    foreach (string guid in kvp.Value.assetGUIDs)\n                    {\n                        if (refs.ContainsKey(guid)) continue;\n\n                        AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                        refs.Add(guid, new AssetFinderRef(0, 1, asset, null, null)\n                        {\n                            isSceneRef = false,\n                            group = kvp.Value.bundleGroup\n                        });\n\n                        map.Add(guid, kvp.Value);\n                        if (maxLengthGroup.Length < kvp.Value.address.Length)\n                        {\n                            maxLengthGroup = kvp.Value.address;\n                        }\n                    }\n\n                    foreach (string guid in kvp.Value.childGUIDs)\n                    {\n                        if (refs.ContainsKey(guid)) continue;\n\n                        AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                        refs.Add(guid, new AssetFinderRef(0, 1, asset, null, null)\n                        {\n                            isSceneRef = false,\n                            group = kvp.Value.bundleGroup\n                        });\n\n                        map.Add(guid, kvp.Value);\n                        if (maxLengthGroup.Length < kvp.Value.address.Length)\n                        {\n                            maxLengthGroup = kvp.Value.address;\n                        }\n                    }\n                }\n\n                var miniLabelStyle = EditorStyles.miniLabel ?? new GUIStyle();\n                maxWidth = miniLabelStyle.CalcSize(\n                    AssetFinderGUIContent.FromString(maxLengthGroup)\n                ).x + 16f;\n\n\n                // Find usage\n                Dictionary<string, AssetFinderRef> usages = AssetFinderRef.FindUsage(map.Keys.ToArray());\n                foreach (KeyValuePair<string, AssetFinderRef> kvp in usages)\n                {\n                    if (refs.ContainsKey(kvp.Key)) continue;\n                    AssetFinderRef v = kvp.Value;\n\n                    // do not take script\n                    if (v.asset.IsScript) continue;\n                    if (v.asset.IsExcluded) continue;\n\n                    refs.Add(kvp.Key, kvp.Value);\n                    kvp.Value.depth = 1;\n                    kvp.Value.group = AUTO_DEPEND_TITLE;\n                }\n            }\n\n            dirty = false;\n            drawer.SetRefs(refs);\n        }\n\n        internal void RefreshSort()\n        {\n            drawer.RefreshSort();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAddressableDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1f842a83edda6e42a6c4ea4dc024049\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroup.cs",
    "content": "using System.Collections.Generic;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderAssetGroup\n    {\n        public string name;\n        public HashSet<string> extension;\n        public AssetFinderAssetGroup(string name, params string[] exts)\n        {\n            this.name = name;\n            extension = new HashSet<string>();\n            for (var i = 0; i < exts.Length; i++)\n            {\n                extension.Add(exts[i]);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroup.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bd3abcb0505d46544820add49a5c7377\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroupDrawer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n\n    internal static class AssetFinderAssetGroupDrawer\n    {\n        // ------------------------------- STATIC -----------------------------\n\n        internal static readonly AssetFinderAssetGroup[] FILTERS =\n        {\n            new AssetFinderAssetGroup(\"Scene\", \".unity\"),\n            new AssetFinderAssetGroup(\"Prefab\", \".prefab\"),\n            new AssetFinderAssetGroup(\"Model\", \".3df\", \".3dm\", \".3dmf\", \".3dv\", \".3dx\", \".c5d\", \".lwo\", \".lws\", \".ma\", \".mb\",\n                \".mesh\", \".vrl\", \".wrl\", \".wrz\", \".fbx\", \".dae\", \".3ds\", \".dxf\", \".obj\", \".skp\", \".max\", \".blend\"),\n            new AssetFinderAssetGroup(\"Material\", \".mat\", \".cubemap\", \".physicsmaterial\"),\n            new AssetFinderAssetGroup(\"Texture\", \".ai\", \".apng\", \".png\", \".bmp\", \".cdr\", \".dib\", \".eps\", \".exif\", \".ico\", \".icon\",\n                \".j\", \".j2c\", \".j2k\", \".jas\", \".jiff\", \".jng\", \".jp2\", \".jpc\", \".jpe\", \".jpeg\", \".jpf\", \".jpg\", \"jpw\",\n                \"jpx\", \"jtf\", \".mac\", \".omf\", \".qif\", \".qti\", \"qtif\", \".tex\", \".tfw\", \".tga\", \".tif\", \".tiff\", \".wmf\",\n                \".psd\", \".exr\", \".rendertexture\"),\n            new AssetFinderAssetGroup(\"Video\", \".asf\", \".asx\", \".avi\", \".dat\", \".divx\", \".dvx\", \".mlv\", \".m2l\", \".m2t\", \".m2ts\",\n                \".m2v\", \".m4e\", \".m4v\", \"mjp\", \".mov\", \".movie\", \".mp21\", \".mp4\", \".mpe\", \".mpeg\", \".mpg\", \".mpv2\",\n                \".ogm\", \".qt\", \".rm\", \".rmvb\", \".wmv\", \".xvid\", \".flv\"),\n            new AssetFinderAssetGroup(\"Audio\", \".mp3\", \".wav\", \".ogg\", \".aif\", \".aiff\", \".mod\", \".it\", \".s3m\", \".xm\"),\n            new AssetFinderAssetGroup(\"Script\", \".cs\", \".js\", \".boo\", \".h\"),\n            new AssetFinderAssetGroup(\"Text\", \".txt\", \".json\", \".xml\", \".bytes\", \".sql\"),\n            new AssetFinderAssetGroup(\"Shader\", \".shader\", \".cginc\", \".shadervariants\"),\n            new AssetFinderAssetGroup(\"Animation\", \".anim\", \".controller\", \".overridecontroller\", \".mask\"),\n            new AssetFinderAssetGroup(\"Font\", \".ttf\", \".otf\", \".dfont\", \".ttc\"),\n            new AssetFinderAssetGroup(\"Unity Asset\", \".asset\", \".guiskin\", \".flare\", \".fontsettings\", \".prefs\", \".playable\", \".signal\"),\n            new AssetFinderAssetGroup(\"Others\") //\n        };\n\n        private static AssetFinderIgnoreDrawer _ignore;\n        private static AssetFinderIgnoreDrawer ignore\n        {\n            get\n            {\n                if (_ignore == null) _ignore = new AssetFinderIgnoreDrawer();\n\n                return _ignore;\n            }\n        }\n\n        public static int GetIndex(string ext)\n        {\n            // Normalize extension to lowercase for case-insensitive comparison\n            string normalizedExt = ext?.ToLowerInvariant() ?? \"\";\n            \n            for (var i = 0; i < FILTERS.Length - 1; i++)\n            {\n                if (FILTERS[i].extension.Contains(normalizedExt)) return i;\n            }\n\n            return FILTERS.Length - 1; //Others\n        }\n\n        public static bool DrawSearchFilter()\n        {\n            int n = FILTERS.Length;\n            var nCols = 4;\n            int nRows = Mathf.CeilToInt(n / (float)nCols);\n            var result = false;\n\n            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);\n            {\n                if (GUILayout.Button(\"All\", EditorStyles.toolbarButton) && !AssetFinderSetting.IsIncludeAllType())\n                {\n                    AssetFinderSetting.IncludeAllType();\n                    result = true;\n                }\n\n                if (GUILayout.Button(\"None\", EditorStyles.toolbarButton) && (AssetFinderSetting.GetExcludeType() != -1))\n                {\n                    AssetFinderSetting.ExcludeAllType();\n                    result = true;\n                }\n            }\n            EditorGUILayout.EndHorizontal();\n\n            GUILayout.BeginHorizontal();\n            for (var i = 0; i < nCols; i++)\n            {\n                GUILayout.BeginVertical();\n                for (var j = 0; j < nRows; j++)\n                {\n                    int idx = i * nCols + j;\n                    if (idx >= n) break;\n\n                    bool s = !AssetFinderSetting.IsTypeExcluded(idx);\n                    bool s1 = GUILayout.Toggle(s, FILTERS[idx].name);\n                    if (s1 != s)\n                    {\n                        result = true;\n                        AssetFinderSetting.ToggleTypeExclude(idx);\n                    }\n                }\n\n                GUILayout.EndVertical();\n                if ((i + 1) * nCols >= n) break;\n            }\n\n            GUILayout.EndHorizontal();\n\n            return result;\n        }\n\n        public static void SetDirtyIgnore()\n        {\n            ignore.SetDirty();\n        }\n\n        public static bool DrawIgnoreFolder()\n        {\n            var change = false;\n            ignore.Draw();\n            return change;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetGroupDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 253072b20ae7c4f4d8119fcba52ca790\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetOrganizer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderAssetOrganizer : IRefDraw\n    {\n        // Processing state and dependencies\n        private readonly IWindow _window;\n        private bool _isProcessing;\n        private float _progress;\n        private string _currentFolderPath;\n        private HashSet<string> _foldersToProcess = new HashSet<string>();\n        private Dictionary<string, List<string>> _assetsToMove = new Dictionary<string, List<string>>();\n        private List<PlannedMove> _plannedMoves = new List<PlannedMove>();\n        \n        // Results tracking\n        private Dictionary<string, int> _organizedFolders = new Dictionary<string, int>();\n        private List<string> _errorAssets = new List<string>();\n        private string _reportTitle;\n        \n        // Settings backup\n        private AssetFinderAutoRefreshMode _originalAutoRefreshMode;\n\n        // Asset classification\n        private static readonly string[] SpecialFolders = {\"/Editor/\", \"/Resources/\", \"/StreamingAssets/\", \"/Gizmos/\", \"/Plugins/\", \"/Standard Assets/\"};\n        private static readonly string[] ScriptExtensions = { \".cs\", \".js\", \".boo\" };\n        private HashSet<string> _spriteAtlasFolders = new HashSet<string>();\n        private Dictionary<string, SpriteAtlasInfo> _spriteAtlasInfo = new Dictionary<string, SpriteAtlasInfo>();\n        private Dictionary<string, SpineAssetInfo> _spineAssetInfo = new Dictionary<string, SpineAssetInfo>();\n        private HashSet<string> _spineAssets = new HashSet<string>();\n\n        internal AssetFinderAssetOrganizer(IWindow window, Func<AssetFinderRefDrawer.Sort> getSort, Func<AssetFinderRefDrawer.Mode> getGroup)\n        {\n            _window = window;\n        }\n\n        public IWindow window => _window;\n\n        public int ElementCount()\n        {\n            return _organizedFolders.Count + _errorAssets.Count;\n        }\n\n        public bool Draw(Rect rect)\n        {\n            GUI.BeginClip(rect);\n            GUILayout.BeginArea(new Rect(0, 0, rect.width, rect.height));\n            \n            bool result = DrawLayout();\n            \n            GUILayout.EndArea();\n            GUI.EndClip();\n            return result;\n        }\n\n        public bool DrawLayout()\n        {\n            GUILayout.BeginVertical();\n            {\n                if (_isProcessing)\n                {\n                    DrawProgressBar();\n                }\n                else\n                {\n                    DrawSelectedFolders();\n                    \n                    GUILayout.Space(10);\n\n                    bool hasFoldersSelected = _foldersToProcess.Count > 0;\n                    GUI.enabled = hasFoldersSelected;\n                    if (GUILayout.Button(\"Organize Selected Folder\" + (hasFoldersSelected && _foldersToProcess.Count > 1 ? \"s\" : \"\"), AssetFinderTheme.Current.ActionButtonHeight))\n                    {\n                        StartProcessing();\n                    }\n                    GUI.enabled = true;\n\n                    if (!hasFoldersSelected)\n                    {\n                        EditorGUILayout.HelpBox(\"Please select one or more folders in the Project panel to organize.\", MessageType.Info);\n                    }\n\n                    if (!string.IsNullOrEmpty(_reportTitle))\n                    {\n                        EditorGUILayout.HelpBox(_reportTitle, MessageType.Info);\n                    }\n                    \n                    if (_organizedFolders.Count > 0)\n                    {\n                        GUILayout.Space(10);\n                        EditorGUILayout.LabelField(\"Organized Assets:\", EditorStyles.boldLabel);\n                        \n                        GUILayout.BeginVertical(EditorStyles.helpBox);\n                        foreach (var folder in _organizedFolders.OrderBy(f => f.Key))\n                        {\n                            EditorGUILayout.LabelField($\"{folder.Key}: {folder.Value} assets\", EditorStyles.miniLabel);\n                        }\n                        GUILayout.EndVertical();\n                    }\n                    \n                    if (_errorAssets.Count > 0)\n                    {\n                        GUILayout.Space(10);\n                        EditorGUILayout.LabelField(\"Errors:\", EditorStyles.boldLabel);\n                        \n                        GUILayout.BeginVertical(EditorStyles.helpBox);\n                        foreach (string error in _errorAssets.Take(10))\n                        {\n                            EditorGUILayout.LabelField(error, EditorStyles.miniLabel);\n                        }\n                        \n                        if (_errorAssets.Count > 10)\n                        {\n                            EditorGUILayout.LabelField($\"...and {_errorAssets.Count - 10} more\", EditorStyles.miniLabel);\n                        }\n                        \n                        GUILayout.EndVertical();\n                    }\n                }\n            }\n            GUILayout.EndVertical();\n            GUILayout.FlexibleSpace();\n            return true;\n        }\n\n        private void DrawSelectedFolders()\n        {\n            _foldersToProcess.Clear();\n            \n            foreach (UnityObject obj in Selection.objects)\n            {\n                string path = AssetDatabase.GetAssetPath(obj);\n                if (string.IsNullOrEmpty(path)) continue;\n                \n                if (AssetDatabase.IsValidFolder(path))\n                {\n                    _foldersToProcess.Add(path);\n                }\n            }\n            \n            CleanupSelectionHierarchy();\n            \n            if (_foldersToProcess.Count > 0)\n            {\n                EditorGUILayout.LabelField(\"Selected Folders:\", EditorStyles.boldLabel);\n                \n                GUILayout.BeginVertical(EditorStyles.helpBox);\n                foreach (string folder in _foldersToProcess.OrderBy(f => f))\n                {\n                    EditorGUILayout.LabelField(folder, EditorStyles.miniLabel);\n                }\n                GUILayout.EndVertical();\n            }\n        }\n        \n        private void CleanupSelectionHierarchy()\n        {\n            var foldersToRemove = new HashSet<string>();\n            \n            foreach (string folder in _foldersToProcess)\n            {\n                foreach (string otherFolder in _foldersToProcess)\n                {\n                    if (folder != otherFolder && folder.StartsWith(otherFolder + \"/\"))\n                    {\n                        foldersToRemove.Add(folder);\n                    }\n                }\n            }\n            \n            foreach (string folderToRemove in foldersToRemove)\n            {\n                _foldersToProcess.Remove(folderToRemove);\n            }\n        }\n\n        private void DrawProgressBar()\n        {\n            EditorGUILayout.Space();\n            EditorGUILayout.LabelField(\"Organizing assets...\", EditorStyles.boldLabel);\n            \n            Rect rect = AssetFinderTheme.Current.GetProgressBarRect();\n            EditorGUI.ProgressBar(rect, _progress, _currentFolderPath);\n            \n            EditorGUILayout.Space();\n                            if (GUILayout.Button(\"Cancel\", AssetFinderTheme.Current.CancelButtonHeight))\n            {\n                CancelProcessing();\n            }\n        }\n\n        private void StartProcessing()\n        {\n            DisableAutoRefresh();\n            _isProcessing = true;\n            _progress = 0f;\n            _currentFolderPath = string.Empty;\n            _organizedFolders.Clear();\n            _errorAssets.Clear();\n            _assetsToMove.Clear();\n            _plannedMoves.Clear();\n            _reportTitle = null;\n            _spriteAtlasFolders.Clear();\n            _spriteAtlasInfo.Clear();\n            _spineAssetInfo.Clear();\n            _spineAssets.Clear();\n            \n            AnalyzeSpineAssets();\n            AnalyzeSpriteAtlases();\n            \n            foreach (string folderPath in _foldersToProcess)\n            {\n                AnalyzeFolder(folderPath);\n            }\n            \n            CleanupEmptyMoveEntries();\n            \n            var scriptMoves = new Dictionary<string, List<string>>();\n            var nonScriptMoves = new Dictionary<string, List<string>>();\n            foreach (var kvp in _assetsToMove)\n            {\n                var scripts = new List<string>();\n                var nonScripts = new List<string>();\n                foreach (var assetPath in kvp.Value)\n                {\n                    string ext = Path.GetExtension(assetPath).ToLowerInvariant();\n                    if (ScriptExtensions.Contains(ext)) scripts.Add(assetPath);\n                    else nonScripts.Add(assetPath);\n                }\n                if (nonScripts.Count > 0) nonScriptMoves[kvp.Key] = nonScripts;\n                if (scripts.Count > 0) scriptMoves[kvp.Key] = scripts;\n            }\n            _assetsToMove.Clear();\n            foreach (var kvp in nonScriptMoves)\n            {\n                _assetsToMove[kvp.Key] = kvp.Value;\n            }\n\n            foreach (var kvp in scriptMoves)\n            {\n                _assetsToMove[kvp.Key] = kvp.Value;\n            }\n\n            PlanAllMoves();\n            \n            if (_plannedMoves.Count == 0)\n            {\n                _reportTitle = \"No assets needed to be organized.\";\n                CleanupAfterProcessing();\n                return;\n            }\n            \n            EditorApplication.update -= ProcessNextBatch;\n            EditorApplication.update += ProcessNextBatch;\n        }\n        \n        private void CancelProcessing()\n        {\n            _isProcessing = false;\n            CleanupAfterProcessing();\n        }\n\n        private void CleanupAfterProcessing()\n        {\n            _isProcessing = false;\n            RestoreAutoRefreshMode();\n            AssetFinderDeleteEmptyFolder.DeleteAllEmptyFoldersRecursive(\"Assets\");\n            AssetDatabase.Refresh();\n            _window.Repaint();\n        }\n        \n        private void DisableAutoRefresh()\n        {\n            _originalAutoRefreshMode = AssetFinderSettingExt.autoRefreshMode;\n            AssetFinderSettingExt.autoRefreshMode = AssetFinderAutoRefreshMode.Off;\n        }\n        \n        private void RestoreAutoRefreshMode()\n        {\n            AssetFinderSettingExt.autoRefreshMode = _originalAutoRefreshMode;\n        }\n        \n        private void AnalyzeSpineAssets()\n        {\n            string[] spineGUIDs = AssetDatabase.FindAssets(\"t:SkeletonDataAsset\");\n            foreach (string guid in spineGUIDs)\n            {\n                string skeletonPath = AssetDatabase.GUIDToAssetPath(guid);\n                UnityObject skeletonAsset = AssetDatabase.LoadAssetAtPath<UnityObject>(skeletonPath);\n                if (skeletonAsset != null)\n                {\n                    string skeletonName = Path.GetFileNameWithoutExtension(skeletonPath);\n                    if (skeletonName.EndsWith(\"_SkeletonData\"))\n                    {\n                        skeletonName = skeletonName.Substring(0, skeletonName.Length - \"_SkeletonData\".Length);\n                    }\n                    \n                    var spineInfo = new SpineAssetInfo { skeletonPath = skeletonPath, spineName = skeletonName };\n                    spineInfo.assets.Add(skeletonPath);\n                    _spineAssets.Add(skeletonPath);\n                    \n                    SerializedObject so = new SerializedObject(skeletonAsset);\n                    SerializedProperty iterator = so.GetIterator();\n                    while (iterator.NextVisible(true))\n                    {\n                        if (iterator.propertyType == SerializedPropertyType.ObjectReference && iterator.objectReferenceValue != null)\n                        {\n                            string refPath = AssetDatabase.GetAssetPath(iterator.objectReferenceValue);\n                            if (!string.IsNullOrEmpty(refPath) && refPath != skeletonPath)\n                            {\n                                spineInfo.assets.Add(refPath);\n                                _spineAssets.Add(refPath);\n                            }\n                        }\n                    }\n                    \n                    _spineAssetInfo[skeletonPath] = spineInfo;\n                }\n            }\n        }\n        \n        private void AnalyzeSpriteAtlases()\n        {\n            string[] atlasGUIDs = AssetDatabase.FindAssets(\"t:SpriteAtlas\");\n            foreach (string guid in atlasGUIDs)\n            {\n                string atlasPath = AssetDatabase.GUIDToAssetPath(guid);\n                UnityObject atlasAsset = AssetDatabase.LoadAssetAtPath<UnityObject>(atlasPath);\n                if (atlasAsset != null)\n                {\n                    var atlasInfo = new SpriteAtlasInfo { atlasPath = atlasPath };\n                    SerializedObject so = new SerializedObject(atlasAsset);\n                    SerializedProperty objectsForPacking = so.FindProperty(\"m_EditorData.packables\");\n                    if (objectsForPacking != null && objectsForPacking.isArray)\n                    {\n                        for (int i = 0; i < objectsForPacking.arraySize; i++)\n                        {\n                            SerializedProperty element = objectsForPacking.GetArrayElementAtIndex(i);\n                            UnityObject obj = element.objectReferenceValue;\n                            if (obj != null)\n                            {\n                                string objPath = AssetDatabase.GetAssetPath(obj);\n                                if (AssetDatabase.IsValidFolder(objPath))\n                                {\n                                    _spriteAtlasFolders.Add(objPath);\n                                    atlasInfo.folders.Add(objPath);\n                                }\n                                else\n                                {\n                                    atlasInfo.sprites.Add(objPath);\n                                }\n                            }\n                        }\n                    }\n                    _spriteAtlasInfo[atlasPath] = atlasInfo;\n                }\n            }\n        }\n        \n        private void AnalyzeFolder(string folderPath)\n        {\n            if (string.IsNullOrEmpty(folderPath)) return;\n            if (!AssetDatabase.IsValidFolder(folderPath)) return;\n\n            string[] assetGUIDs = AssetDatabase.FindAssets(\"*\", new[] { folderPath });\n\n            foreach (string guid in assetGUIDs)\n            {\n                string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n\n                if (AssetDatabase.IsValidFolder(assetPath) || assetPath.EndsWith(\".meta\"))\n                    continue;\n\n                string assetPathLower = assetPath.Replace('\\\\', '/').ToLowerInvariant();\n                bool inSpecial = SpecialFolders.Any(sf => assetPathLower.Contains(sf.ToLowerInvariant()));\n                if (inSpecial) continue;\n                \n                if (IsSpineAsset(assetPath)) continue;\n                if (IsInSpriteAtlasFolder(assetPath)) continue;\n\n                string extension = Path.GetExtension(assetPath).ToLowerInvariant();\n                string folderType = DetermineFolderType(assetPath, extension);\n                \n                string targetFolderPath = $\"{folderPath}/{folderType}\";\n                string currentAssetFolder = Path.GetDirectoryName(assetPath);\n                \n                if (NormalizePath(currentAssetFolder).Equals(NormalizePath(targetFolderPath), StringComparison.OrdinalIgnoreCase))\n                    continue;\n                \n                string key = folderPath + \"|\" + folderType;\n                if (!_assetsToMove.ContainsKey(key)) _assetsToMove[key] = new List<string>();\n                _assetsToMove[key].Add(assetPath);\n            }\n            \n            foreach (var spineInfo in _spineAssetInfo.Values)\n            {\n                bool anyAssetInFolder = spineInfo.assets.Any(asset => asset.StartsWith(folderPath + \"/\") || asset == folderPath);\n                if (anyAssetInFolder)\n                {\n                    string targetPath = folderPath + \"/Spines/\" + spineInfo.spineName;\n                    string key = targetPath + \"|SPINE_GROUP|\" + spineInfo.spineName;\n                    if (!_assetsToMove.ContainsKey(key)) _assetsToMove[key] = new List<string>();\n                    foreach (string asset in spineInfo.assets)\n                    {\n                        if (asset.StartsWith(folderPath + \"/\") || asset == folderPath)\n                        {\n                            string currentAssetFolder = Path.GetDirectoryName(asset);\n                            if (!NormalizePath(currentAssetFolder).Equals(NormalizePath(targetPath), StringComparison.OrdinalIgnoreCase))\n                            {\n                                _assetsToMove[key].Add(asset);\n                            }\n                        }\n                    }\n                }\n            }\n            \n            foreach (var atlasInfo in _spriteAtlasInfo.Values)\n            {\n                if (atlasInfo.atlasPath.StartsWith(folderPath + \"/\") || atlasInfo.atlasPath == folderPath)\n                {\n                    string atlasName = Path.GetFileNameWithoutExtension(atlasInfo.atlasPath);\n                    string targetPath = folderPath + \"/SpriteAtlas\";\n                    \n                    string currentAtlasFolder = Path.GetDirectoryName(atlasInfo.atlasPath);\n                    if (!NormalizePath(currentAtlasFolder).Equals(NormalizePath(targetPath), StringComparison.OrdinalIgnoreCase))\n                    {\n                        string atlasKey = targetPath + \"|ATLAS|\" + atlasName;\n                        if (!_assetsToMove.ContainsKey(atlasKey)) _assetsToMove[atlasKey] = new List<string>();\n                        _assetsToMove[atlasKey].Add(atlasInfo.atlasPath);\n                    }\n                    \n                    if (atlasInfo.folders.Count == 1 && atlasInfo.sprites.Count == 0)\n                    {\n                        string singleFolder = atlasInfo.folders[0];\n                        if (singleFolder.StartsWith(folderPath + \"/\") || singleFolder == folderPath)\n                        {\n                            string expectedFolderPath = Path.Combine(targetPath, atlasName);\n                            if (!NormalizePath(singleFolder).Equals(NormalizePath(expectedFolderPath), StringComparison.OrdinalIgnoreCase))\n                            {\n                                string folderKey = targetPath + \"|ATLAS_FOLDER|\" + atlasName;\n                                if (!_assetsToMove.ContainsKey(folderKey)) _assetsToMove[folderKey] = new List<string>();\n                                _assetsToMove[folderKey].Add(singleFolder);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        \n        private bool IsSpineAsset(string assetPath)\n        {\n            return _spineAssets.Contains(assetPath);\n        }\n        \n        private bool IsInSpriteAtlasFolder(string assetPath)\n        {\n            return _spriteAtlasFolders.Any(folder => assetPath.StartsWith(folder + \"/\"));\n        }\n        \n        private string DetermineFolderType(string assetPath, string extension)\n        {\n            if (extension == \".shadervariants\")\n            {\n                return \"Shaders\";\n            }\n            \n            if (extension == \".lighting\")\n            {\n                return \"Scenes\";\n            }\n            \n            if (extension == \".asset\")\n            {\n                Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);\n                if (assetType != null)\n                {\n                    string typeName = assetType.Name;\n                    if (typeName == \"LightingDataAsset\" || typeName == \"LightingSettings\")\n                    {\n                        return \"Scenes\";\n                    }\n                    if (typeName == \"TMPro_FontAsset\" || typeName.Contains(\"FontAsset\"))\n                    {\n                        return \"Fonts\";\n                    }\n                    if (typeName == \"Mesh\")\n                    {\n                        return \"Models\";\n                    }\n                    if (typeName == \"AnimationClip\")\n                    {\n                        return \"Animations\";\n                    }\n                }\n            }\n            \n            if (IsTextureImportedAsSprite(assetPath))\n            {\n                return \"Sprites\";\n            }\n            \n            string folderType = GetAssetFolderType(extension);\n            if (folderType == \"Others\")\n            {\n                Type mainType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);\n                if (mainType != null)\n                {\n                    string typeName = mainType.Name;\n                    string specialType = GetAssetFolderTypeByTypeName(typeName);\n                    if (specialType != null) folderType = specialType;\n                    else folderType = typeName;\n                }\n            }\n            return folderType;\n        }\n        \n        private bool IsTextureImportedAsSprite(string assetPath)\n        {\n            AssetImporter importer = AssetImporter.GetAtPath(assetPath);\n            if (importer is TextureImporter textureImporter)\n            {\n                return textureImporter.textureType == TextureImporterType.Sprite;\n            }\n            return false;\n        }\n\n        private string GetAssetFolderTypeByTypeName(string typeName)\n        {\n            for (int i = 0; i < AssetFinderAssetGroupDrawer.FILTERS.Length - 1; i++)\n            {\n                AssetFinderAssetGroup filter = AssetFinderAssetGroupDrawer.FILTERS[i];\n                if (!string.IsNullOrEmpty(filter.name) && filter.name.Equals(typeName, StringComparison.OrdinalIgnoreCase))\n                {\n                    return filter.name + \"s\";\n                }\n            }\n            return null;\n        }\n        \n        private void PlanAllMoves()\n        {\n            var planned = new List<PlannedMove>();\n            var usedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);\n            \n            foreach (var kvp in _assetsToMove)\n            {\n                string[] parts = kvp.Key.Split('|');\n                string parentFolder = parts[0];\n                string folderType = parts[1];\n                \n                if (parts.Length > 2 && (parts[1] == \"SPINE_GROUP\" || parts[1] == \"ATLAS\" || parts[1] == \"ATLAS_FOLDER\"))\n                {\n                    string newName = parts[2];\n                    string targetFolderPath = parentFolder;\n                    string absTargetFolder = AssetPathToAbs(targetFolderPath);\n                    if (!Directory.Exists(absTargetFolder)) Directory.CreateDirectory(absTargetFolder);\n                    \n                    if (parts[1] == \"SPINE_GROUP\")\n                    {\n                        foreach (string assetPath in kvp.Value)\n                        {\n                            string srcAbs = AssetPathToAbs(assetPath);\n                            string fileName = Path.GetFileName(assetPath);\n                            string dstAbs = Path.Combine(absTargetFolder, fileName);\n                            \n                            if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase))\n                                continue;\n                            \n                            planned.Add(new PlannedMove {\n                                srcAsset = srcAbs,\n                                srcMeta = srcAbs + \".meta\",\n                                dstAsset = dstAbs,\n                                dstMeta = dstAbs + \".meta\",\n                                isFolder = false\n                            });\n                        }\n                    }\n                    else if (parts[1] == \"ATLAS\")\n                    {\n                        foreach (string assetPath in kvp.Value)\n                        {\n                            string srcAbs = AssetPathToAbs(assetPath);\n                            string fileName = Path.GetFileName(assetPath);\n                            string dstAbs = Path.Combine(absTargetFolder, fileName);\n                            \n                            if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase))\n                                continue;\n                            \n                            planned.Add(new PlannedMove {\n                                srcAsset = srcAbs,\n                                srcMeta = srcAbs + \".meta\",\n                                dstAsset = dstAbs,\n                                dstMeta = dstAbs + \".meta\",\n                                isFolder = false\n                            });\n                        }\n                    }\n                    else if (parts[1] == \"ATLAS_FOLDER\")\n                    {\n                        foreach (string folderPath in kvp.Value)\n                        {\n                            string srcAbs = AssetPathToAbs(folderPath);\n                            string dstAbs = Path.Combine(absTargetFolder, newName);\n                            \n                            if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase))\n                                continue;\n                            \n                            planned.Add(new PlannedMove {\n                                srcAsset = srcAbs,\n                                srcMeta = srcAbs + \".meta\",\n                                dstAsset = dstAbs,\n                                dstMeta = dstAbs + \".meta\",\n                                isFolder = true\n                            });\n                        }\n                    }\n                    continue;\n                }\n                \n                string targetFolderPath2 = $\"{parentFolder}/{folderType}\";\n                string absTargetFolder2 = AssetPathToAbs(targetFolderPath2);\n                if (!Directory.Exists(absTargetFolder2)) Directory.CreateDirectory(absTargetFolder2);\n                \n                foreach (string assetPath in kvp.Value)\n                {\n                    string fileName = Path.GetFileName(assetPath);\n                    string baseName = Path.GetFileNameWithoutExtension(fileName);\n                    string ext = Path.GetExtension(fileName);\n                    string srcAbs = AssetPathToAbs(assetPath);\n                    string srcMeta = srcAbs + \".meta\";\n                    string dstName = fileName;\n                    \n                    string dstAbs = Path.Combine(absTargetFolder2, dstName);\n                    string dstMeta = dstAbs + \".meta\";\n                    int suffix = 1;\n                    \n                    while (usedNames.Contains(dstAbs) || (File.Exists(dstAbs) && !NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase)))\n                    {\n                        dstName = $\"{baseName}-{suffix.ToString(\"D2\")}{ext}\";\n                        dstAbs = Path.Combine(absTargetFolder2, dstName);\n                        dstMeta = dstAbs + \".meta\";\n                        suffix++;\n                    }\n                    \n                    if (NormalizePath(srcAbs).Equals(NormalizePath(dstAbs), StringComparison.OrdinalIgnoreCase))\n                        continue;\n                    \n                    usedNames.Add(dstAbs);\n                    planned.Add(new PlannedMove {\n                        srcAsset = srcAbs,\n                        srcMeta = srcMeta,\n                        dstAsset = dstAbs,\n                        dstMeta = dstMeta\n                    });\n                }\n            }\n            _plannedMoves = planned;\n        }\n\n        private static string AssetPathToAbs(string assetPath)\n        {\n            if (assetPath.StartsWith(\"Assets/\"))\n                return Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), assetPath);\n            if (assetPath.StartsWith(\"Assets\"))\n                return Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), assetPath);\n            return assetPath;\n        }\n        \n        private void ProcessNextBatch()\n        {\n            if (!_isProcessing)\n            {\n                EditorApplication.update -= ProcessNextBatch;\n                CleanupAfterProcessing();\n                return;\n            }\n            \n            int batchSize = 10;\n            int moved = 0;\n            while (_plannedMoves.Count > 0 && moved < batchSize)\n            {\n                var move = _plannedMoves[0];\n                _plannedMoves.RemoveAt(0);\n                \n                if (move.isFolder)\n                {\n                    if (!NormalizePath(move.srcAsset).Equals(NormalizePath(move.dstAsset), StringComparison.OrdinalIgnoreCase))\n                    {\n                        if (Directory.Exists(move.dstAsset)) Directory.Delete(move.dstAsset, true);\n                        Directory.Move(move.srcAsset, move.dstAsset);\n                    }\n                    if (File.Exists(move.srcMeta) && !NormalizePath(move.srcMeta).Equals(NormalizePath(move.dstMeta), StringComparison.OrdinalIgnoreCase))\n                    {\n                        if (File.Exists(move.dstMeta)) File.Delete(move.dstMeta);\n                        File.Move(move.srcMeta, move.dstMeta);\n                    }\n                    string folderType = Path.GetFileName(Path.GetDirectoryName(move.dstAsset));\n                    if (!_organizedFolders.ContainsKey(folderType)) _organizedFolders[folderType] = 1;\n                    else _organizedFolders[folderType]++;\n                }\n                else\n                {\n                    if (!NormalizePath(move.srcAsset).Equals(NormalizePath(move.dstAsset), StringComparison.OrdinalIgnoreCase))\n                    {\n                        if (File.Exists(move.dstAsset)) File.Delete(move.dstAsset);\n                        if (File.Exists(move.srcAsset))\n                        {\n                            File.Move(move.srcAsset, move.dstAsset);\n                        }\n                        else\n                        {\n                            _errorAssets.Add($\"Source file not found: {move.srcAsset}\");\n                            moved++;\n                            continue;\n                        }\n                    }\n                    if (File.Exists(move.srcMeta) && !NormalizePath(move.srcMeta).Equals(NormalizePath(move.dstMeta), StringComparison.OrdinalIgnoreCase))\n                    {\n                        if (File.Exists(move.dstMeta)) File.Delete(move.dstMeta);\n                        File.Move(move.srcMeta, move.dstMeta);\n                    }\n                    string folderType = Path.GetFileName(Path.GetDirectoryName(move.dstAsset));\n                    if (!_organizedFolders.ContainsKey(folderType)) _organizedFolders[folderType] = 1;\n                    else _organizedFolders[folderType]++;\n                }\n                moved++;\n            }\n            _progress = 1f - (_plannedMoves.Count / (float)(1 + _plannedMoves.Count));\n            if (_plannedMoves.Count == 0)\n            {\n                int totalAssets = _organizedFolders.Values.Sum();\n                _reportTitle = totalAssets > 0 \n                    ? $\"Successfully organized {totalAssets} assets into {_organizedFolders.Count} category folders!\" \n                    : \"No assets needed to be organized.\";\n                if (_errorAssets.Count > 0)\n                {\n                    _reportTitle += $\" Encountered {_errorAssets.Count} errors.\";\n                }\n                EditorApplication.update -= ProcessNextBatch;\n                AssetDatabase.Refresh();\n                CleanupAfterProcessing();\n            }\n            _window.Repaint();\n        }\n        \n        private void DeleteEmptySubfolders(string parentFolder)\n        {\n            DeleteEmptyFoldersRecursive(parentFolder);\n        }\n\n        private static void DeleteEmptyFoldersRecursive(string root)\n        {\n            if (!Directory.Exists(root)) return;\n            foreach (var dir in Directory.GetDirectories(root))\n            {\n                var dirName = Path.GetFileName(dir);\n                if (dirName.StartsWith(\".\")) continue;\n                DeleteEmptyFoldersRecursive(dir.Replace(\"\\\\\", \"/\"));\n                if (IsUnityFolderEmptyStatic(dir.Replace(\"\\\\\", \"/\")))\n                {\n                    string relPath = \"Assets\" + dir.Replace(Application.dataPath, \"\").Replace(\"\\\\\", \"/\");\n                    AssetDatabase.DeleteAsset(relPath);\n                }\n            }\n        }\n        \n        private static bool IsUnityFolderEmptyStatic(string folder)\n        {\n            var files = Directory.GetFiles(folder);\n            foreach (var file in files)\n            {\n                var fileName = Path.GetFileName(file);\n                if (fileName == null) continue;\n                if (fileName.StartsWith(\".\")) return false;\n                if (!fileName.EndsWith(\".meta\", StringComparison.OrdinalIgnoreCase)) return false;\n            }\n            var dirs = Directory.GetDirectories(folder);\n            foreach (var dir in dirs)\n            {\n                var dirName = Path.GetFileName(dir);\n                if (dirName.StartsWith(\".\")) return false;\n                if (!IsUnityFolderEmptyStatic(dir.Replace(\"\\\\\", \"/\"))) return false;\n            }\n            return true;\n        }\n        \n        private string GetAssetFolderType(string extension)\n        {\n            // Normalize extension to lowercase for case-insensitive comparison\n            string normalizedExt = extension?.ToLowerInvariant() ?? \"\";\n            \n            for (int i = 0; i < AssetFinderAssetGroupDrawer.FILTERS.Length - 1; i++)\n            {\n                AssetFinderAssetGroup filter = AssetFinderAssetGroupDrawer.FILTERS[i];\n                if (filter.extension.Contains(normalizedExt))\n                {\n                    return filter.name + \"s\";\n                }\n            }\n            \n            return \"Others\";\n        }\n\n        private class PlannedMove {\n            public string srcAsset;\n            public string srcMeta;\n            public string dstAsset;\n            public string dstMeta;\n            public bool isFolder;\n        }\n        \n        private class SpriteAtlasInfo {\n            public string atlasPath;\n            public List<string> folders = new List<string>();\n            public List<string> sprites = new List<string>();\n        }\n        \n        private class SpineAssetInfo {\n            public string skeletonPath;\n            public string spineName;\n            public List<string> assets = new List<string>();\n        }\n\n        private void CleanupEmptyMoveEntries()\n        {\n            var keysToRemove = new List<string>();\n            foreach (var kvp in _assetsToMove)\n            {\n                if (kvp.Value.Count == 0)\n                {\n                    keysToRemove.Add(kvp.Key);\n                }\n            }\n            foreach (string key in keysToRemove)\n            {\n                _assetsToMove.Remove(key);\n            }\n        }\n        \n        private static string NormalizePath(string path)\n        {\n            return path.Replace('\\\\', '/').TrimEnd('/');\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderAssetOrganizer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 994fa27b9be091e499e68d19ffd1f368\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderBookmark.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderBookmark : IRefDraw\n    {\n        internal static readonly HashSet<string> guidSet = new HashSet<string>();\n        internal static readonly HashSet<string> instSet = new HashSet<string>(); // Do not reference directly to SceneObject (which might be destroyed anytime)\n\n        // ------------ instance\n        private static bool dirty;\n        private readonly AssetFinderRefDrawer drawer;\n        internal Dictionary<string, AssetFinderRef> refs = new Dictionary<string, AssetFinderRef>();\n\n        public AssetFinderBookmark(IWindow window, Func<AssetFinderRefDrawer.Sort> getSortMode, Func<AssetFinderRefDrawer.Mode> getGroupMode)\n        {\n            this.window = window;\n\t\t\tdrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n\t\t\t{\n\t\t\t\twindow = window,\n\t\t\t\tgetSortMode = getSortMode,\n\t\t\t\tgetGroupMode = getGroupMode,\n\t\t\t\tshowFullPath = false,\n\t\t\t\tshowFileSize = false,\n\t\t\t\tshowExtension = true,\n\t\t\t\tshowUsageType = false,\n\t\t\t\tshowAssetBundleName = false,\n\t\t\t\tshowAtlasName = false,\n\t\t\t\tshowToggle = true,\n\t\t\t\tshowHighlight = false,\n\t\t\t\tshouldShowExtension = () => true,\n\t\t\t\tshouldShowDetailButton = () => true,\n\t\t\t\tonCacheInvalidated = () => { } // Bookmark panel manages its own state\n\t\t\t})\n            {\n                messageNoRefs = \"Do bookmark something!\",\n                groupDrawer =\n                {\n                    hideGroupIfPossible = true\n                },\n                level0Group = string.Empty,\n                paddingLeft = -16f\n            };\n\n            dirty = true;\n            drawer.SetDirty();\n        }\n\n        public static int Count => guidSet.Count + instSet.Count;\n\n        public IWindow window { get; set; }\n\n        public int ElementCount()\n        {\n            return refs == null ? 0 : refs.Count;\n        }\n\n        public bool DrawLayout()\n        {\n            if (dirty) RefreshView();\n            return drawer.DrawLayout();\n        }\n\n        public bool Draw(Rect rect)\n        {\n            if (dirty) RefreshView();\n            if (refs == null)\n            {\n                AssetFinderLOG.LogWarning(\"Refs is null!\");\n                return false;\n            }\n\n            var bottomRect = new Rect(rect.x + 1f, rect.yMax - 16f, rect.width - 2f, 16f);\n            DrawButtons(bottomRect);\n\n            rect.yMax -= 16f;\n            return drawer.Draw(rect);\n        }\n\n        public static bool Contains(string guidOrInstID)\n        {\n            return guidSet.Contains(guidOrInstID) || instSet.Contains(guidOrInstID);\n        }\n\n        public static bool Contains(UnityObject sceneObject)\n        {\n            var id = sceneObject.GetInstanceID().ToString();\n            return instSet.Contains(id);\n        }\n        public static bool Contains(AssetFinderRef rf)\n        {\n            if (rf.isSceneRef)\n            {\n                if (instSet == null) return false;\n                return instSet.Contains(rf.component.GetInstanceID().ToString());\n            }\n            if (guidSet == null) return false;\n            return guidSet.Contains(rf.asset.guid);\n        }\n        public static void Add(UnityObject sceneObject)\n        {\n            if (sceneObject == null) return;\n            var id = sceneObject.GetInstanceID().ToString();\n            instSet.Add(id);\n            dirty = true;\n        }\n\n        public static void Add(string guid)\n        {\n            if (guidSet.Contains(guid)) return;\n            string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(assetPath))\n            {\n                AssetFinderLOG.LogWarning(\"Invalid GUID: \" + guid);\n                return;\n            }\n\n            guidSet.Add(guid);\n            dirty = true;\n        }\n\n        public static void Remove(UnityObject sceneObject)\n        {\n            if (sceneObject == null) return;\n            var id = sceneObject.GetInstanceID().ToString();\n            instSet.Remove(id);\n            dirty = true;\n        }\n\n        public static void Remove(string guidOrInstID)\n        {\n            guidSet.Remove(guidOrInstID);\n            instSet.Remove(guidOrInstID);\n            dirty = true;\n        }\n\n        public static void Clear()\n        {\n            guidSet.Clear();\n            instSet.Clear();\n            dirty = true;\n        }\n\n        public static void Add(AssetFinderRef rf)\n        {\n\n            if (rf.isSceneRef)\n            {\n                Add(rf.component);\n            } else\n            {\n                Add(rf.asset.guid);\n            }\n            \n            // Invalidate all drawer caches so group toggles update correctly\n            InvalidateAllDrawerCaches();\n        }\n\n        public static void Remove(AssetFinderRef rf)\n        {\n\n            if (rf.isSceneRef)\n\n                //Debug.Log(\"remove: \" + rf.component);\n            {\n                Remove(rf.component);\n            } else\n            {\n                Remove(rf.asset.guid);\n            }\n            \n            // Invalidate all drawer caches so group toggles update correctly\n            InvalidateAllDrawerCaches();\n        }\n\n        public static void Commit()\n        {\n            var list = new HashSet<UnityObject>();\n\n            foreach (string guid in guidSet)\n            {\n                string path = AssetDatabase.GUIDToAssetPath(guid);\n                UnityObject obj = AssetDatabase.LoadAssetAtPath(path, typeof(UnityObject));\n                if (obj != null) list.Add(obj);\n            }\n\n            foreach (string instID in instSet)\n            {\n                int id = int.Parse(instID);\n                UnityObject obj = EditorUtility.InstanceIDToObject(id);\n                if (obj == null) continue;\n                list.Add(obj is Component c ? c.gameObject : obj);\n            }\n\n            Selection.objects = list.ToArray();\n        }\n\n        public void SetDirty()\n        {\n            drawer.SetDirty();\n        }\n\n        private void DrawButtons(Rect rect)\n        {\n            var (selectRect, exportRect) = rect.ExtractLeft(64f, 4f);\n            GUI.enabled = (refs != null) && (refs.Count > 0);\n            {\n                if (GUI.Button(selectRect, AssetFinderGUIContent.FromString(\"Select\", \"Select items in Project or Hierarchy panel\"))) Commit();\n                if (GUI.Button(exportRect, AssetFinderGUIContent.FromString(\"CSV\", \"Export bookmarked items as CSV\"))) AssetFinderExport.ExportCSV(AssetFinderRef.FromDict(refs));    \n            }\n\t\t\tGUI.enabled = true;\n            \n\t\t\t// if (GUI.Button(right, AssetFinderIcon.Refresh.image)) RefreshView();\n        }\n\n        public void RefreshView()\n        {\n\t\t\trefs = new Dictionary<string, AssetFinderRef>();\n\n\t\t\t//foreach (KeyValuePair<string, List<string>> item in AssetFinderSetting.IgnoreFiltered)\n            foreach (string guid in guidSet)\n            {\n\t\t\t\tAssetFinderAsset asset = AssetFinderCache.Api.Get(guid, false);\n\t\t\t\tif (asset == null)\n\t\t\t\t{\n\t\t\t\t\tAssetFinderLOG.LogWarning(\"Invalid asset guid: \" + guid);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\trefs.Add(guid, new AssetFinderRef(0, 1, asset, null));\n            }\n\n\t\t\tforeach (string instID in instSet)\n            {\n\t\t\t\tint id;\n\t\t\t\tif (!int.TryParse(instID, out id)) continue;\n\t\t\t\tvar obj = EditorUtility.InstanceIDToObject(id);\n\t\t\t\tif (obj == null) continue;\n\t\t\t\trefs.Add(instID, new AssetFinderRef(0, 1, null, null) { component = obj, isSceneRef = true });\n            }\n\n            drawer.SetRefs(refs);\n            dirty = false;\n        }\n\n        internal void RefreshSort()\n        {\n            drawer.RefreshSort();\n        }\n\n        \n        // Callback for cache invalidation - set by AssetFinderWindowAll\n        public static System.Action OnBookmarkChanged;\n        \n        private static void InvalidateAllDrawerCaches()\n        {\n            OnBookmarkChanged?.Invoke();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderBookmark.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3ddd7baef5a53d048a4d84bd7fb20e35\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderDeleteEmptyFolder.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderDeleteEmptyFolder : IRefDraw\n    {\n        private readonly IWindow _window;\n        private bool _isProcessing;\n        private float _progress;\n        private List<string> _foldersToDelete = new List<string>();\n        private List<string> _deletedFolders = new List<string>();\n        private string _reportTitle;\n        private int _currentIndex;\n\n        internal AssetFinderDeleteEmptyFolder(IWindow window, Func<AssetFinderRefDrawer.Sort> getSort, Func<AssetFinderRefDrawer.Mode> getGroup)\n        {\n            _window = window;\n        }\n\n        public IWindow window => _window;\n        public int ElementCount() => _deletedFolders.Count;\n\n        public bool Draw(Rect rect)\n        {\n            GUI.BeginClip(rect);\n            GUILayout.BeginArea(new Rect(0, 0, rect.width, rect.height));\n            bool result = DrawLayout();\n            GUILayout.EndArea();\n            GUI.EndClip();\n            return result;\n        }\n\n        public bool DrawLayout()\n        {\n            GUILayout.BeginVertical();\n            if (_isProcessing)\n            {\n                DrawProgressBar();\n            }\n            else\n            {\n                if (GUILayout.Button(\"Delete All Empty Folders\", AssetFinderTheme.Current.ActionButtonHeight))\n                {\n                    StartProcessing();\n                }\n                if (!string.IsNullOrEmpty(_reportTitle))\n                {\n                    EditorGUILayout.HelpBox(_reportTitle, MessageType.Info);\n                }\n                if (_deletedFolders.Count > 0)\n                {\n                    GUILayout.Space(10);\n                    EditorGUILayout.LabelField(\"Deleted Folders:\", EditorStyles.boldLabel);\n                    GUILayout.BeginVertical(EditorStyles.helpBox);\n                    foreach (var folder in _deletedFolders.OrderBy(f => f))\n                    {\n                        EditorGUILayout.LabelField(folder, EditorStyles.miniLabel);\n                    }\n                    GUILayout.EndVertical();\n                }\n            }\n            GUILayout.EndVertical();\n            GUILayout.FlexibleSpace();\n            return true;\n        }\n\n        private void DrawProgressBar()\n        {\n            EditorGUILayout.Space();\n            EditorGUILayout.LabelField(\"Deleting empty folders...\", EditorStyles.boldLabel);\n            Rect rect = AssetFinderTheme.Current.GetProgressBarRect();\n            EditorGUI.ProgressBar(rect, _progress, _currentIndex < _foldersToDelete.Count ? _foldersToDelete[_currentIndex] : \"Done\");\n            EditorGUILayout.Space();\n            if (GUILayout.Button(\"Cancel\", AssetFinderTheme.Current.CancelButtonHeight))\n            {\n                CancelProcessing();\n            }\n        }\n\n        private void StartProcessing()\n        {\n            _isProcessing = true;\n            _progress = 0f;\n            _foldersToDelete.Clear();\n            _deletedFolders.Clear();\n            _reportTitle = null;\n            _currentIndex = 0;\n            FindAllEmptyFolders(\"Assets\");\n            _foldersToDelete = _foldersToDelete.Distinct().OrderByDescending(f => f.Length).ToList();\n            EditorApplication.update -= ProcessNextFolder;\n            EditorApplication.update += ProcessNextFolder;\n        }\n\n        private void CancelProcessing()\n        {\n            _isProcessing = false;\n            EditorApplication.update -= ProcessNextFolder;\n            _window.Repaint();\n        }\n\n        private void ProcessNextFolder()\n        {\n            if (!_isProcessing)\n            {\n                EditorApplication.update -= ProcessNextFolder;\n                return;\n            }\n            if (_currentIndex >= _foldersToDelete.Count)\n            {\n                EditorApplication.update -= ProcessNextFolder;\n                _isProcessing = false;\n                GenerateReport();\n                _window.Repaint();\n                return;\n            }\n            string folder = _foldersToDelete[_currentIndex];\n            _progress = _currentIndex / (float)_foldersToDelete.Count;\n            if (IsFolderEmpty(folder))\n            {\n                AssetDatabase.DeleteAsset(folder);\n                _deletedFolders.Add(folder);\n            }\n            _currentIndex++;\n            _window.Repaint();\n        }\n\n        private void FindAllEmptyFolders(string root)\n        {\n            foreach (var dir in Directory.GetDirectories(root))\n            {\n                var dirName = Path.GetFileName(dir);\n                if (dirName.StartsWith(\".\")) continue; // skip hidden folders\n                FindAllEmptyFolders(dir.Replace(\"\\\\\", \"/\"));\n                if (IsUnityFolderEmpty(dir.Replace(\"\\\\\", \"/\")))\n                {\n                    _foldersToDelete.Add(dir.Replace(\"\\\\\", \"/\"));\n                }\n            }\n        }\n\n        private bool IsUnityFolderEmpty(string folder)\n        {\n            var files = Directory.GetFiles(folder);\n            foreach (var file in files)\n            {\n                var fileName = Path.GetFileName(file);\n                if (fileName == null) continue;\n                if (fileName.StartsWith(\".\")) return false; // hidden file\n                if (!fileName.EndsWith(\".meta\", StringComparison.OrdinalIgnoreCase)) return false; // any non-meta file\n            }\n            var dirs = Directory.GetDirectories(folder);\n            foreach (var dir in dirs)\n            {\n                var dirName = Path.GetFileName(dir);\n                if (dirName.StartsWith(\".\")) return false; // hidden subfolder\n                if (!IsUnityFolderEmpty(dir.Replace(\"\\\\\", \"/\"))) return false;\n            }\n            return true;\n        }\n\n        private bool IsFolderEmpty(string folder)\n        {\n            var files = Directory.GetFiles(folder).Where(f => !f.EndsWith(\".meta\")).ToArray();\n            var dirs = Directory.GetDirectories(folder);\n            return files.Length == 0 && dirs.All(d => !AssetDatabase.IsValidFolder(d) || IsFolderEmpty(d.Replace(\"\\\\\", \"/\")));\n        }\n\n        private void GenerateReport()\n        {\n            if (_deletedFolders.Count > 0)\n            {\n                _reportTitle = $\"Deleted {_deletedFolders.Count} empty folder(s).\";\n            }\n            else\n            {\n                _reportTitle = \"No empty folders found.\";\n            }\n        }\n\n        // Public static method to delete all empty folders recursively from a root\n        public static void DeleteAllEmptyFoldersRecursive(string root)\n        {\n            foreach (var dir in Directory.GetDirectories(root))\n            {\n                var dirName = Path.GetFileName(dir);\n                if (dirName.StartsWith(\".\")) continue; // skip hidden folders\n                DeleteAllEmptyFoldersRecursive(dir.Replace(\"\\\\\", \"/\"));\n                if (IsUnityFolderEmptyStatic(dir.Replace(\"\\\\\", \"/\")))\n                {\n                    string relPath = dir.Replace(\"\\\\\", \"/\");\n                    if (relPath.StartsWith(Application.dataPath))\n                    {\n                        relPath = \"Assets\" + relPath.Substring(Application.dataPath.Length);\n                    }\n                    // Remove any double 'Assets' prefix\n                    while (relPath.StartsWith(\"AssetsAssets/\"))\n                    {\n                        relPath = relPath.Substring(\"Assets\".Length);\n                    }\n                    // Ensure single 'Assets/' at the start\n                    if (!relPath.StartsWith(\"Assets/\"))\n                    {\n                        relPath = \"Assets/\" + relPath.TrimStart('/');\n                    }\n                    // File IO delete: delete folder and .meta file\n                    string absPath = Path.Combine(Application.dataPath.Substring(0, Application.dataPath.Length - 6), relPath); // Remove 'Assets' from Application.dataPath\n                    if (Directory.Exists(absPath))\n                    {\n                        Directory.Delete(absPath, true);\n                    }\n                    string metaPath = absPath + \".meta\";\n                    if (File.Exists(metaPath))\n                    {\n                        File.Delete(metaPath);\n                    }\n                }\n            }\n        }\n        private static bool IsUnityFolderEmptyStatic(string folder)\n        {\n            var files = Directory.GetFiles(folder);\n            foreach (var file in files)\n            {\n                var fileName = Path.GetFileName(file);\n                if (fileName == null) continue;\n                if (fileName.StartsWith(\".\")) return false; // hidden file\n                if (!fileName.EndsWith(\".meta\", StringComparison.OrdinalIgnoreCase)) return false; // any non-meta file\n            }\n            var dirs = Directory.GetDirectories(folder);\n            foreach (var dir in dirs)\n            {\n                var dirName = Path.GetFileName(dir);\n                if (dirName.StartsWith(\".\")) return false; // hidden subfolder\n                if (!IsUnityFolderEmptyStatic(dir.Replace(\"\\\\\", \"/\"))) return false;\n            }\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderDeleteEmptyFolder.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f83f35cc96d96694c80d7bec055f99f8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderIgnoreDrawer.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderIgnoreDrawer\n    {\n        private readonly AssetFinderTreeUI2.GroupDrawer groupIgnore;\n        private bool dirty;\n        private Dictionary<string, AssetFinderRef> refs;\n\n        public AssetFinderIgnoreDrawer()\n        {\n            groupIgnore = new AssetFinderTreeUI2.GroupDrawer(DrawGroup, DrawItem)\n            {\n                hideGroupIfPossible = true\n            };\n\n            ApplyFiter();\n        }\n\n        private void DrawItem(Rect r, string guid)\n        {\n            AssetFinderRef rf;\n            if (!refs.TryGetValue(guid, out rf)) return;\n\n            if (rf.depth == 1) //mode != Mode.Dependency && \n            {\n                Color c = GUI.color;\n                GUI.color = Color.blue;\n                GUI.DrawTexture(new Rect(r.x - 4f, r.y + 2f, 2f, 2f), EditorGUIUtility.whiteTexture);\n                GUI.color = c;\n            }\n\n            rf.asset.Draw(\n                r,\n                new AssetFinderAsset.AssetFinderAssetDrawConfig(\n                    false,\n                true,\n                    false,\n                    false,\n                    false,\n                    false,\n                    null,\n                    true\n                )\n            );\n\n            Rect drawR = r;\n            drawR.x = drawR.x + drawR.width - 50f; // (groupDrawer.TreeNoScroll() ? 60f : 70f) ;\n            drawR.width = 30;\n            drawR.y += 1;\n            drawR.height -= 2;\n\n            if (GUI.Button(drawR, \"X\", EditorStyles.miniButton)) AssetFinderSetting.RemoveIgnore(rf.asset.assetPath);\n        }\n\n        private void DrawGroup(Rect r, string id, int childCound)\n        {\n            GUI.Label(r, AssetFinderGUIContent.FromString(id), EditorStyles.boldLabel);\n            if (childCound <= 1) return;\n\n            Rect drawR = r;\n            drawR.x = drawR.x + drawR.width - 50f; // (groupDrawer.TreeNoScroll() ? 60f : 70f) ;\n            drawR.width = 30;\n            drawR.y += 1;\n            drawR.height -= 2;\n        }\n\n        public void SetDirty()\n        {\n            dirty = true;\n        }\n\n        //private float sizeRatio {\n        //    get{\n        //        if(AssetFinderWindow.window != null)\n        //            return AssetFinderWindow.window.sizeRatio;\n        //        return .3f;\n        //    }\n        //}\n\n        public void Draw()\n        {\n            if (dirty) ApplyFiter();\n\n            GUILayout.BeginHorizontal();\n            {\n                GUILayout.Space(4f);\n                Object[] drops = GUI2.DropZone(\"Drag & Drop folders here to exclude\", 100, 95);\n                if ((drops != null) && (drops.Length > 0))\n                {\n                    for (var i = 0; i < drops.Length; i++)\n                    {\n                        string path = AssetDatabase.GetAssetPath(drops[i]);\n                        if (path.Equals(AssetFinderCache.DEFAULT_CACHE_PATH)) continue;\n                        AssetFinderSetting.AddIgnore(path);\n                    }\n                }\n\n                groupIgnore.DrawLayout();\n            }\n            GUILayout.EndHorizontal();\n        }\n\n\n        private void ApplyFiter()\n        {\n            dirty = false;\n            refs = new Dictionary<string, AssetFinderRef>();\n\n            //foreach (KeyValuePair<string, List<string>> item in AssetFinderSetting.IgnoreFiltered)\n            foreach (string item2 in AssetFinderSetting.s.listIgnore)\n            {\n                string guid = AssetDatabase.AssetPathToGUID(item2);\n                if (string.IsNullOrEmpty(guid)) continue;\n\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid, true);\n                var r = new AssetFinderRef(0, 0, asset, null, \"Ignore\");\n                refs.Add(guid, r);\n            }\n\n            groupIgnore.Reset\n            (\n                refs.Values.ToList(),\n                rf => rf.asset != null ? rf.asset.guid : \"\",\n                GetGroup,\n                SortGroup\n            );\n        }\n\n        private string GetGroup(AssetFinderRef rf)\n        {\n            return \"Ignore\";\n        }\n\n        private void SortGroup(List<string> groups)\n        { }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderIgnoreDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dab80339cf5e1324f9ce59b4af29e79a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderMissingReference.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing UnityEditor;\nusing UnityEditor.SceneManagement;\nusing UnityEngine;\nusing UnityEngine.SceneManagement;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderMissingReference : IRefDraw\n    {\n        // Processing state and dependencies\n        private readonly IWindow _window;\n        private bool _isProcessing;\n        private float _progress;\n        private string _currentAssetPath;\n        private HashSet<string> _processedAssets = new HashSet<string>();\n        private List<string> _assetsToProcess = new List<string>();\n        \n        // Results tracking\n        private Dictionary<string, int> _cleanedAssets = new Dictionary<string, int>();\n        private List<string> _errorAssets = new List<string>();\n        private string _reportTitle;\n        private StringBuilder _report = new StringBuilder();\n        \n        // Scene handling\n        private List<string> _originalScenePaths = new List<string>();\n        private Scene? _currentlyOpenScene = null;\n        \n        // Settings backup\n        private AssetFinderAutoRefreshMode _originalAutoRefreshMode;\n\n        internal AssetFinderMissingReference(IWindow window, Func<AssetFinderRefDrawer.Sort> getSort, Func<AssetFinderRefDrawer.Mode> getGroup)\n        {\n            _window = window;\n            // Note: getSort and getGroup are unused but kept for interface compatibility\n        }\n\n        public IWindow window => _window;\n\n        public int ElementCount()\n        {\n            return _cleanedAssets.Count + _errorAssets.Count;\n        }\n\n        public bool Draw(Rect rect)\n        {\n            GUI.BeginClip(rect);\n            GUILayout.BeginArea(new Rect(0, 0, rect.width, rect.height));\n            \n            bool result = DrawLayout();\n            \n            GUILayout.EndArea();\n            GUI.EndClip();\n            return result;\n        }\n\n        public bool DrawLayout()\n        {\n            GUILayout.BeginVertical();\n            {\n                if (_isProcessing)\n                {\n                    DrawProgressBar();\n                }\n                else\n                {\n                    if (GUILayout.Button(\"Scan & Remove Missing Scripts\", AssetFinderTheme.Current.ActionButtonHeight))\n                    {\n                        StartProcessing();\n                    }\n\n                    // Display report title if available\n                    if (!string.IsNullOrEmpty(_reportTitle)) \n                        EditorGUILayout.HelpBox(_reportTitle, MessageType.Info);\n                    \n                    // Show full report button if there are results\n                    if (_cleanedAssets.Count > 0 || _errorAssets.Count > 0)\n                    {\n                        if (GUILayout.Button(\"Full Report\"))\n                        {\n                            AssetFinderLOG.Log(_report.ToString());\n                        }\n                    }\n                }\n            }\n            GUILayout.EndVertical();\n            GUILayout.FlexibleSpace();\n            return true;\n        }\n\n        private void DrawProgressBar()\n        {\n            EditorGUILayout.Space();\n            EditorGUILayout.LabelField(\"Processing assets...\", EditorStyles.boldLabel);\n            \n            Rect rect = AssetFinderTheme.Current.GetProgressBarRect();\n            EditorGUI.ProgressBar(rect, _progress, \n                $\"Processing {_currentAssetPath} ({_processedAssets.Count}/{_assetsToProcess.Count})\");\n            \n            EditorGUILayout.Space();\n            if (GUILayout.Button(\"Cancel\", AssetFinderTheme.Current.CancelButtonHeight))\n            {\n                CancelProcessing();\n            }\n        }\n\n        private void StartProcessing()\n        {\n            try\n            {\n                DisableAutoRefresh();\n                SaveCurrentSceneSetup();\n                \n                _isProcessing = true;\n                _progress = 0f;\n                _currentAssetPath = string.Empty;\n                _processedAssets.Clear();\n                _assetsToProcess.Clear();\n                _cleanedAssets.Clear();\n                _errorAssets.Clear();\n                _report.Clear();\n\n                CollectAssetsToProcess();\n                SortAssetsByDependencyOrder();\n\n                EditorApplication.update -= ProcessNextAsset;\n                EditorApplication.update += ProcessNextAsset;\n            }\n            catch (Exception ex)\n            {\n                AssetFinderLOG.LogError($\"Error starting processing: {ex.Message}\");\n                CleanupAfterProcessing();\n            }\n        }\n        \n        private void CancelProcessing()\n        {\n            _isProcessing = false;\n            CleanupAfterProcessing();\n        }\n\n        private void CleanupAfterProcessing()\n        {\n            _isProcessing = false;\n            RestoreOriginalScenes();\n            RestoreAutoRefreshMode();\n            _window.Repaint();\n        }\n        \n        private void ProcessNextAsset()\n        {\n            if (!_isProcessing)\n            {\n                EditorApplication.update -= ProcessNextAsset;\n                CleanupAfterProcessing();\n                return;\n            }\n\n            if (_processedAssets.Count >= _assetsToProcess.Count)\n            {\n                EditorApplication.update -= ProcessNextAsset;\n                GenerateReport();\n                CleanupAfterProcessing();\n                return;\n            }\n\n            string assetPath = _assetsToProcess[_processedAssets.Count];\n            _currentAssetPath = assetPath;\n            _progress = _processedAssets.Count / (float)_assetsToProcess.Count;\n\n            try\n            {\n                if (assetPath.EndsWith(\".unity\"))\n                {\n                    ProcessScene(assetPath);\n                }\n                else if (assetPath.EndsWith(\".prefab\"))\n                {\n                    ProcessPrefab(assetPath);\n                }\n            }\n            catch (Exception ex)\n            {\n                AssetFinderLOG.LogError($\"Error processing {assetPath}: {ex.Message}\");\n                _errorAssets.Add(assetPath);\n            }\n            \n            _processedAssets.Add(assetPath);\n            _window.Repaint();\n        }\n        \n        private void DisableAutoRefresh()\n        {\n            _originalAutoRefreshMode = AssetFinderSettingExt.autoRefreshMode;\n            AssetFinderSettingExt.autoRefreshMode = AssetFinderAutoRefreshMode.Off;\n        }\n        \n        private void RestoreAutoRefreshMode()\n        {\n            AssetFinderSettingExt.autoRefreshMode = _originalAutoRefreshMode;\n        }\n        \n        private void SaveCurrentSceneSetup()\n        {\n            _originalScenePaths.Clear();\n            \n            for (int i = 0; i < SceneManager.sceneCount; i++)\n            {\n                Scene scene = SceneManager.GetSceneAt(i);\n                if (!string.IsNullOrEmpty(scene.path))\n                {\n                    _originalScenePaths.Add(scene.path);\n                }\n            }\n        }\n\n        private void RestoreOriginalScenes()\n        {\n            try\n            {\n                _currentlyOpenScene = null;\n                \n                if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())\n                {\n                    return;\n                }\n                \n                EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);\n                \n                for (int i = 0; i < _originalScenePaths.Count; i++)\n                {\n                    string scenePath = _originalScenePaths[i];\n                    OpenSceneMode mode = i == 0 ? OpenSceneMode.Single : OpenSceneMode.Additive;\n                    EditorSceneManager.OpenScene(scenePath, mode);\n                }\n            }\n            catch (Exception ex)\n            {\n                AssetFinderLOG.LogError($\"Error restoring original scenes: {ex.Message}\");\n            }\n        }\n        \n        private void CollectAssetsToProcess()\n        {\n            AddAssetTypeToPipeline(\"t:Prefab\");\n            AddAssetTypeToPipeline(\"t:Scene\");\n        }\n        \n        private void AddAssetTypeToPipeline(string assetTypeFilter)\n        {\n            string[] guids = AssetDatabase.FindAssets(assetTypeFilter, new[] { \"Assets\" });\n            foreach (string guid in guids)\n            {\n                _assetsToProcess.Add(AssetDatabase.GUIDToAssetPath(guid));\n            }\n        }\n\n        private void SortAssetsByDependencyOrder()\n        {\n            Dictionary<string, List<string>> dependencies = BuildDependencyGraph(out Dictionary<string, List<string>> dependents);\n            Dictionary<string, int> assetLevels = CalculateAssetLevels(dependencies);\n            \n            _assetsToProcess = _assetsToProcess\n                .OrderBy(path => assetLevels[path])\n                .ToList();\n        }\n        \n        private Dictionary<string, List<string>> BuildDependencyGraph(out Dictionary<string, List<string>> dependents)\n        {\n            Dictionary<string, List<string>> dependencies = new Dictionary<string, List<string>>();\n            dependents = new Dictionary<string, List<string>>();\n            \n            foreach (string assetPath in _assetsToProcess)\n            {\n                dependencies[assetPath] = new List<string>();\n                dependents[assetPath] = new List<string>();\n            }\n            \n            foreach (string assetPath in _assetsToProcess)\n            {\n                string[] dependencyPaths = AssetDatabase.GetDependencies(assetPath, false);\n                foreach (string depPath in dependencyPaths)\n                {\n                    if (_assetsToProcess.Contains(depPath) && depPath != assetPath)\n                    {\n                        dependencies[assetPath].Add(depPath);\n                        dependents[depPath].Add(assetPath);\n                    }\n                }\n            }\n            \n            return dependencies;\n        }\n        \n        private Dictionary<string, int> CalculateAssetLevels(Dictionary<string, List<string>> dependencies)\n        {\n            Dictionary<string, int> assetLevels = new Dictionary<string, int>();\n            HashSet<string> processed = new HashSet<string>();\n            \n            // First pass: assign level 0 to assets with no dependencies\n            foreach (string assetPath in _assetsToProcess)\n            {\n                if (dependencies[assetPath].Count == 0)\n                {\n                    assetLevels[assetPath] = 0;\n                    processed.Add(assetPath);\n                }\n            }\n            \n            // Process remaining assets\n            bool changesMade = true;\n            int currentLevel = 0;\n            \n            while (changesMade && processed.Count < _assetsToProcess.Count)\n            {\n                currentLevel++;\n                changesMade = false;\n                \n                foreach (string assetPath in _assetsToProcess)\n                {\n                    if (processed.Contains(assetPath)) continue;\n                    \n                    bool allDepsProcessed = true;\n                    foreach (string dep in dependencies[assetPath])\n                    {\n                        if (!processed.Contains(dep))\n                        {\n                            allDepsProcessed = false;\n                            break;\n                        }\n                    }\n                    \n                    if (allDepsProcessed)\n                    {\n                        assetLevels[assetPath] = currentLevel;\n                        processed.Add(assetPath);\n                        changesMade = true;\n                    }\n                }\n            }\n            \n            // Handle circular dependencies by assigning them to the next level\n            if (processed.Count < _assetsToProcess.Count)\n            {\n                currentLevel++;\n                foreach (string assetPath in _assetsToProcess)\n                {\n                    if (!processed.Contains(assetPath))\n                    {\n                        assetLevels[assetPath] = currentLevel;\n                    }\n                }\n            }\n            \n            return assetLevels;\n        }\n        \n        private void GenerateReport()\n        {\n            _report.Clear();\n            \n            int totalRemovedScripts = _cleanedAssets.Values.Sum();\n            \n            if (_cleanedAssets.Count > 0)\n            {\n                _reportTitle = $\"Removed missing scripts from {_cleanedAssets.Count} assets!\";\n                _report.AppendLine($\"Removed {totalRemovedScripts} missing script(s) from {_cleanedAssets.Count} assets:\");\n                \n                foreach (var asset in _cleanedAssets.OrderBy(x => x.Key))\n                {\n                    _report.AppendLine($\"- {asset.Key}: {asset.Value} script(s) removed\");\n                }\n                _report.AppendLine();\n            }\n            else\n            {\n                _reportTitle = \"No missing scripts were found to remove.\";\n                _report.AppendLine(\"No missing scripts were found to remove.\");\n                _report.AppendLine();\n            }\n            \n            if (_errorAssets.Count > 0)\n            {\n                _report.AppendLine($\"Errors occurred in {_errorAssets.Count} assets:\");\n                foreach (string asset in _errorAssets.OrderBy(x => x))\n                {\n                    _report.AppendLine($\"- {asset}\");\n                }\n            }\n        }\n        \n        private void ProcessPrefab(string prefabPath)\n        {\n            try\n            {\n                GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);\n                if (prefabAsset == null) return;\n\n                GameObject prefabInstance = PrefabUtility.InstantiatePrefab(prefabAsset) as GameObject;\n                if (prefabInstance == null) return;\n                \n                try\n                {\n                    int removedCount = RemoveMissingScriptsFromGameObject(prefabInstance);\n                    \n                    if (removedCount > 0)\n                    {\n                        PrefabUtility.ApplyPrefabInstance(prefabInstance, InteractionMode.AutomatedAction);\n                        _cleanedAssets[prefabPath] = removedCount;\n                        AssetDatabase.SaveAssets();\n                    }\n                }\n                finally\n                {\n                    UnityObject.DestroyImmediate(prefabInstance);\n                }\n            }\n            catch (Exception ex)\n            {\n                AssetFinderLOG.LogError($\"Error processing prefab {prefabPath}: {ex.Message}\");\n                _errorAssets.Add(prefabPath);\n            }\n        }\n        \n        private void ProcessScene(string scenePath)\n        {\n            if (_currentlyOpenScene.HasValue && EditorSceneManager.GetActiveScene().isDirty)\n            {\n                EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());\n                _currentlyOpenScene = null;\n            }\n            \n            Scene scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);\n            _currentlyOpenScene = scene;\n            \n            int removedCount = 0;\n            foreach (GameObject rootObj in scene.GetRootGameObjects())\n            {\n                removedCount += RemoveMissingScriptsFromGameObject(rootObj);\n            }\n            \n            if (removedCount > 0)\n            {\n                EditorSceneManager.SaveScene(scene);\n                _cleanedAssets[scenePath] = removedCount;\n            }\n        }\n        \n        private int RemoveMissingScriptsFromGameObject(GameObject gameObject)\n        {\n            int removedCount = 0;\n            \n            int missingCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject);\n            if (missingCount > 0)\n            {\n                GameObjectUtility.RemoveMonoBehavioursWithMissingScript(gameObject);\n                removedCount += missingCount;\n            }\n            \n            foreach (Transform child in gameObject.transform)\n            {\n                removedCount += RemoveMissingScriptsFromGameObject(child.gameObject);\n            }\n            \n            return removedCount;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderMissingReference.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5c3cf0d585651d34a80d39be086bc224\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderSetting.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Serialization;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [Serializable]\n    internal class AssetFinderSetting\n    {\n        private static AssetFinderSetting d;\n\n        [NonSerialized] private static HashSet<string> _hashIgnore;\n\n        //\t\tprivate static Dictionary<string, List<string>> _IgnoreFiltered;\n        public static Action OnIgnoreChange;\n\n        public bool alternateColor = true;\n        public int excludeTypes; //32-bit type Mask\n\n        public List<string> listIgnore = new List<string>();\n        // public bool pingRow = true;\n        public bool referenceCount = true;\n        // public bool showPackageAsset = true;\n        public bool showSubAssetFileId;\n\n        public bool showFileSize;\n        public bool displayFileSize = true;\n        public bool displayAtlasName;\n        public bool displayAssetBundleName;\n\n        public bool showUsedByClassed = true;\n        public int treeIndent = 10;\n        public bool manualRefreshSelection;\n\n        public Color32 rowColor = new Color32(0, 0, 0, 12);\n\n        // public Color32 ScanColor = new Color32(0, 204, 102, 255);\n        public Color SelectedColor = new Color(0, 0f, 1f, 0.25f);\n\n\n        //public bool scanScripts\t\t= false;\n\n\n\n        /*\n        Doesn't have a settings option - I will include one in next update\n\n        2. Hide the reference number - Should be in the setting above so will be coming next\n        3. Cache file path should be configurable - coming next in the setting\n        4. Disable / Selectable color in alternative rows - coming next in the setting panel\n        5. Applied filters aren't saved - Should be fixed in next update too\n        6. Hide Selection part - should be com as an option so you can quickly toggle it on or off\n        7. Click whole line to ping - coming next by default and can adjustable in the setting panel\n\n        */\n\n        internal static AssetFinderSetting s\n        {\n            get\n            {\n                if (AssetFinderCache.Api != null) return AssetFinderCache.Api.setting;\n                if (d != null) return d;\n                d = new AssetFinderSetting();\n                return d;\n            }\n        }\n\n        public static bool ShowUsedByClassed => s.showUsedByClassed;\n\n        public static bool ShowFileSize => s.showFileSize;\n\n        public static int TreeIndent\n        {\n            get => s.treeIndent;\n            set\n            {\n                if (s.treeIndent == value) return;\n\n                s.treeIndent = value;\n                setDirty();\n            }\n        }\n\n        public static bool ShowReferenceCount\n        {\n            get => s.referenceCount;\n            set\n            {\n                if (s.referenceCount == value) return;\n\n                s.referenceCount = value;\n                setDirty();\n            }\n        }\n        public static bool AlternateRowColor\n        {\n            get => s.alternateColor;\n            set\n            {\n                if (s.alternateColor == value) return;\n\n                s.alternateColor = value;\n                setDirty();\n            }\n        }\n\n        public static Color32 RowColor\n        {\n            get => s.rowColor;\n            set\n            {\n                if (s.rowColor.Equals(value)) return;\n\n                s.rowColor = value;\n                setDirty();\n            }\n        }\n\n        // public static bool PingRow\n        // {\n        //     get => s.pingRow;\n        //     set\n        //     {\n        //         if (s.pingRow == value) return;\n        //\n        //         s.pingRow = value;\n        //         setDirty();\n        //     }\n        // }\n\n        public static bool ManualRefreshSelection\n        {\n            get => s.manualRefreshSelection;\n            set\n            {\n                if (s.manualRefreshSelection == value) return;\n                s.manualRefreshSelection = value;\n                setDirty();\n            }\n        }\n\n        public static HashSet<string> IgnoreAsset\n        {\n            get\n            {\n                if (_hashIgnore != null) return _hashIgnore;\n                _hashIgnore = new HashSet<string>();\n                if (s?.listIgnore == null) return _hashIgnore;\n\n                for (var i = 0; i < s.listIgnore.Count; i++)\n                {\n                    _hashIgnore.Add(s.listIgnore[i]);\n                }\n\n                return _hashIgnore;\n            }\n        }\n\n        //\t\tpublic static Dictionary<string, List<string>> IgnoreFiltered\n        //\t\t{\n        //\t\t\tget\n        //\t\t\t{\n        //\t\t\t\tif (_IgnoreFiltered == null)\n        //\t\t\t\t{\n        //\t\t\t\t\tinitIgnoreFiltered();\n        //\t\t\t\t}\n        //\n        //\t\t\t\treturn _IgnoreFiltered;\n        //\t\t\t}\n        //\t\t}\n\n        //static public bool ScanScripts\n        //{\n        //\tget  { return s.scanScripts; }\n        //\tset  {\n        //\t\tif (s.scanScripts == value) return;\n        //\t\ts.scanScripts = value; setDirty();\n        //\t}\n        //}\n\n        // public static AssetFinderRefDrawer.Mode GroupMode\n        // {\n        //     get => s.groupMode;\n        //     set\n        //     {\n        //         if (s.groupMode.Equals(value)) return;\n        //\n        //         s.groupMode = value;\n        //         setDirty();\n        //     }\n        // }\n        //\n        // public static AssetFinderRefDrawer.Sort SortMode\n        // {\n        //     get => s.sortMode;\n        //     set\n        //     {\n        //         if (s.sortMode.Equals(value)) return;\n        //\n        //         s.sortMode = value;\n        //         setDirty();\n        //     }\n        // }\n\n        public static bool HasTypeExcluded => s.excludeTypes != 0;\n\n        private static void setDirty()\n        {\n            if (AssetFinderCache.Api != null) EditorUtility.SetDirty(AssetFinderCache.Api);\n        }\n\n        //\t\tprivate static void initIgnoreFiltered()\n        //\t\t{\n        //\t\t\tAssetFinderAsset.ignoreTS = Time.realtimeSinceStartup;\n        //\n        //\t\t\t_IgnoreFiltered = new Dictionary<string, List<string>>();\n        //\t\t\tvar lst = new List<string>(s.listIgnore);\n        //\t\t\tlst = lst.OrderBy(x => x.Length).ToList();\n        //\t\t\tint count = lst.Count;\n        //\t\t\tfor (var i = 0; i < count; i++)\n        //\t\t\t{\n        //\t\t\t\tstring str = lst[i];\n        //\t\t\t\t_IgnoreFiltered.Add(str, new List<string> {str});\n        //\t\t\t\tfor (int j = count - 1; j > i; j--)\n        //\t\t\t\t{\n        //\t\t\t\t\tif (lst[j].StartsWith(str))\n        //\t\t\t\t\t{\n        //\t\t\t\t\t\t_IgnoreFiltered[str].Add(lst[j]);\n        //\t\t\t\t\t\tlst.RemoveAt(j);\n        //\t\t\t\t\t\tcount--;\n        //\t\t\t\t\t}\n        //\t\t\t\t}\n        //\t\t\t}\n        //\t\t}\n\n        public static void AddIgnore(string path)\n        {\n            if (string.IsNullOrEmpty(path) || IgnoreAsset.Contains(path) || path == \"Assets\") return;\n\n            s.listIgnore.Add(path);\n            _hashIgnore.Add(path);\n            AssetFinderAssetGroupDrawer.SetDirtyIgnore();\n            AssetFinderCacheHelper.InitIgnore();\n\n            //initIgnoreFiltered();\n\n            AssetFinderAsset.ignoreTS = Time.realtimeSinceStartup;\n            if (OnIgnoreChange != null) OnIgnoreChange();\n        }\n\n\n        public static void RemoveIgnore(string path)\n        {\n            if (!IgnoreAsset.Contains(path)) return;\n\n            _hashIgnore.Remove(path);\n            s.listIgnore.Remove(path);\n            AssetFinderAssetGroupDrawer.SetDirtyIgnore();\n            AssetFinderCacheHelper.InitIgnore();\n\n            //initIgnoreFiltered();\n\n            AssetFinderAsset.ignoreTS = Time.realtimeSinceStartup;\n            if (OnIgnoreChange != null) OnIgnoreChange();\n        }\n\n        public static bool IsTypeExcluded(int type)\n        {\n            return ((s.excludeTypes >> type) & 1) != 0;\n        }\n\n        public static void ToggleTypeExclude(int type)\n        {\n            bool v = ((s.excludeTypes >> type) & 1) != 0;\n            if (v)\n            {\n                s.excludeTypes &= ~(1 << type);\n            } else\n            {\n                s.excludeTypes |= 1 << type;\n            }\n\n            setDirty();\n        }\n\n        public static int GetExcludeType()\n        {\n            return s.excludeTypes;\n        }\n\n        public static bool IsIncludeAllType()\n        {\n            // Debug.Log ((AssetType.FILTERS.Length & s.excludeTypes) + \"  \" + Mathf.Pow(2, AssetType.FILTERS.Length) ); \n            return s.excludeTypes == 0 || Mathf.Abs(s.excludeTypes) == Mathf.Pow(2, AssetFinderAssetGroupDrawer.FILTERS.Length);\n        }\n\n        public static void ExcludeAllType()\n        {\n            s.excludeTypes = -1;\n        }\n\n        public static void IncludeAllType()\n        {\n            s.excludeTypes = 0;\n        }\n\n        public void DrawSettings()\n        {\n            EditorGUI.BeginChangeCheck();\n            {\n                s.alternateColor = EditorGUILayout.Toggle(\"Alternate Row Color\", s.alternateColor);\n                s.showUsedByClassed = EditorGUILayout.Toggle(\"Show Usage Icon\", s.showUsedByClassed);\n                // s.pingRow = EditorGUILayout.Toggle(\"Ping Row\", s.pingRow);\n                s.referenceCount = EditorGUILayout.Toggle(\"Reference Count\", s.referenceCount);\n                // s.showPackageAsset = EditorGUILayout.Toggle(\"Show Package Assets\", s.showPackageAsset);\n                // s.showSubAssetFileId = EditorGUILayout.Toggle(\"Show Sub Asset File ID\", s.showSubAssetFileId);\n                // s.showFileSize = EditorGUILayout.Toggle(\"Show File Size\", s.showFileSize);\n            }\n            if (EditorGUI.EndChangeCheck())\n            {\n                setDirty();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderSetting.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 84c3e9e57209fbc45b591d007e25f316\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderUsedInBuild.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderUsedInBuild : IRefDraw\n    {\n        private readonly AssetFinderRefDrawer drawer;\n        private readonly AssetFinderTreeUI2.GroupDrawer groupDrawer;\n\n        private bool dirty;\n        internal Dictionary<string, AssetFinderRef> refs;\n\n        public AssetFinderUsedInBuild(IWindow window, Func<AssetFinderRefDrawer.Sort> getSortMode, Func<AssetFinderRefDrawer.Mode> getGroupMode)\n        {\n            this.window = window;\n            drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = window,\n                getSortMode = getSortMode,\n                getGroupMode = getGroupMode,\n                showFullPath = false,\n                showFileSize = true,\n                showExtension = true,\n                showUsageType = false,\n                showAssetBundleName = false,\n                showAtlasName = false\n            })\n            {\n                messageNoRefs = \"No scene enabled in Build Settings!\"\n            };\n\n            dirty = true;\n            drawer.SetDirty();\n        }\n\n        public IWindow window { get; set; }\n        \n        // Expose internal drawer for display property access\n        public AssetFinderRefDrawer Drawer => drawer;\n\n\n        public int ElementCount()\n        {\n            return refs?.Count ?? 0;\n        }\n\n        public bool Draw(Rect rect)\n        {\n            if (dirty) RefreshView();\n            return drawer.Draw(rect);\n        }\n\n        public bool DrawLayout()\n        {\n            if (dirty) RefreshView();\n            return drawer.DrawLayout();\n        }\n\n        public void SetDirty()\n        {\n            dirty = true;\n            drawer.SetDirty();\n        }\n\n        public void RefreshView()\n        {\n            var scenes = new HashSet<string>();\n\n            foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)\n            {\n                if (scene == null) continue;\n                if (scene.enabled == false) continue;\n                string sce = AssetDatabase.AssetPathToGUID(scene.path);\n                if (scenes.Contains(sce)) continue;\n                scenes.Add(sce);\n            }\n\n            refs = new Dictionary<string, AssetFinderRef>();\n            Dictionary<string, AssetFinderRef> directRefs = AssetFinderRef.FindUsage(scenes.ToArray());\n            foreach (string scene in scenes)\n            {\n                if (!directRefs.TryGetValue(scene, out AssetFinderRef asset)) continue;\n                asset.depth = 1;\n            }\n\n            List<AssetFinderAsset> list = AssetFinderCache.Api.AssetList;\n            int count = list.Count;\n\n            // Collect assets in Resources / Streaming Assets\n            for (var i = 0; i < count; i++)\n            {\n                AssetFinderAsset item = list[i];\n                if (item.inEditor) continue;\n                if (item.IsExcluded) continue;\n                if (item.IsFolder) continue;\n                if (!item.assetPath.StartsWith(\"Assets/\", StringComparison.Ordinal)) continue;\n\n                if (item.inResources || item.inStreamingAsset || item.inPlugins || item.forcedIncludedInBuild\n                    || !string.IsNullOrEmpty(item.AssetBundleName)\n                    || !string.IsNullOrEmpty(item.AtlasName))\n                {\n                    if (refs.ContainsKey(item.guid)) continue;\n                    refs.Add(item.guid, new AssetFinderRef(0, 1, item, null));\n                }\n            }\n\n            // Collect direct references\n            foreach (KeyValuePair<string, AssetFinderRef> kvp in directRefs)\n            {\n                AssetFinderAsset item = kvp.Value.asset;\n                if (item.inEditor) continue;\n                if (item.IsExcluded) continue;\n                if (!item.assetPath.StartsWith(\"Assets/\", StringComparison.Ordinal)) continue;\n                if (refs.ContainsKey(item.guid)) continue;\n                refs.Add(item.guid, new AssetFinderRef(0, 1, item, null));\n            }\n\n            drawer.SetRefs(refs);\n            dirty = false;\n        }\n\n        internal void RefreshSort()\n        {\n            drawer.RefreshSort();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer/AssetFinderUsedInBuild.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6480768d52898e346865d2e94ba43ffd\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Drawer.meta",
    "content": "fileFormatVersion: 2\nguid: b8dc12b3e4ad4bb8ac5cea3451bbc66f\ntimeCreated: 1746365376"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderChunk.cs",
    "content": "using System.IO;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderChunk\n    {\n        public byte[] buffer;\n        public string file;\n        public long size;\n        public FileStream stream;\n        public bool streamError;\n        public bool streamInited;\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderChunk.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bbaa77776ba63e24bbc227ec3072fc43\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderDuplicateTree2.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderDuplicateTree2 : IRefDraw\n    {\n        private const float TimeDelayDelete = .5f;\n\n        private static readonly AssetFinderFileCompare fc = new AssetFinderFileCompare();\n        private readonly Func<AssetFinderRefDrawer.Mode> getGroupMode;\n\n        private readonly Func<AssetFinderRefDrawer.Sort> getSortMode;\n        private readonly AssetFinderTreeUI2.GroupDrawer groupDrawer;\n        private readonly string searchTerm = \"\";\n        private List<List<string>> cacheAssetList;\n        public bool caseSensitive = false;\n        private Dictionary<string, List<AssetFinderRef>> dicIndex; //index, list\n\n        private bool dirty;\n        private int excludeCount;\n        private string guidPressDelete;\n\n        internal List<AssetFinderRef> list;\n        internal Dictionary<string, AssetFinderRef> refs;\n        public int scanExcludeByIgnoreCount;\n        public int scanExcludeByTypeCount;\n        private float TimePressDelete;\n        \n        // New fields for verification UI\n        private Dictionary<string, string> groupVerificationStatus = new Dictionary<string, string>();\n        private Dictionary<string, float> groupVerificationProgress = new Dictionary<string, float>();\n        private Dictionary<string, int> groupVerificationOrder = new Dictionary<string, int>();\n        private bool isSignatureScanComplete = false;\n\n        // Add enum for progress state\n        private enum ProgressState\n        {\n            Idle,\n            Scanning,\n            Verifying,\n            Complete\n        }\n        private ProgressState progressState = ProgressState.Idle;\n\n        public AssetFinderDuplicateTree2(IWindow window, Func<AssetFinderRefDrawer.Sort> getSortMode, Func<AssetFinderRefDrawer.Mode> getGroupMode)\n        {\n            this.window = window;\n            this.getSortMode = getSortMode;\n            this.getGroupMode = getGroupMode;\n            groupDrawer = new AssetFinderTreeUI2.GroupDrawer(DrawGroup, DrawAsset);\n        }\n\n        public IWindow window { get; set; }\n\n        public bool Draw(Rect rect)\n        {\n            return false;\n        }\n\n        public bool DrawLayout()\n        {\n            if (dirty) RefreshView(cacheAssetList);\n\n            // Show progress bar on top based on progressState\n            if (progressState == ProgressState.Scanning || progressState == ProgressState.Verifying)\n            {\n                float p = fc.nScaned / (float)Mathf.Max(1, fc.nChunks2);\n                string label = progressState == ProgressState.Scanning ? \"Scanning\" : \"Verifying\";\n                Rect progressRect = GUILayoutUtility.GetRect(1, Screen.width, 18f, 18f);\n                EditorGUI.ProgressBar(progressRect, p, string.Format($\"{label} {{0}} / {{1}}\", fc.nScaned, fc.nChunks2));\n                GUILayout.Space(2);\n            }\n\n            // Update progress state based on fc\n            if (fc.nChunks2 > 0 && fc.nScaned < fc.nChunks2)\n            {\n                if (progressState != ProgressState.Scanning && progressState != ProgressState.Verifying)\n                    progressState = ProgressState.Scanning;\n            }\n            else if (fc.nChunks2 > 0 && fc.nScaned >= fc.nChunks2)\n            {\n                if (progressState != ProgressState.Complete)\n                    progressState = ProgressState.Complete;\n            }\n            else\n            {\n                progressState = ProgressState.Idle;\n            }\n\n            if (progressState == ProgressState.Complete || progressState == ProgressState.Idle)\n            {\n                if (groupDrawer.hasValidTree) groupDrawer.tree.itemPaddingRight = 60f;\n                groupDrawer.DrawLayout();\n            }\n\n            DrawHeader();\n            return false;\n        }\n\n        public int ElementCount()\n        {\n            return list?.Count ?? 0;\n        }\n\n        private void DrawAsset(Rect r, string guid)\n        {\n            if (!refs.TryGetValue(guid, out AssetFinderRef rf)) return;\n            var assetRect = r;\n            assetRect.width -= 70f;\n            rf.asset.Draw(\n                assetRect,\n                new AssetFinderAsset.AssetFinderAssetDrawConfig(\n                    false,\n                getGroupMode() != AssetFinderRefDrawer.Mode.Folder,\n                AssetFinderSetting.ShowFileSize,\n                AssetFinderSetting.s.displayAssetBundleName,\n                AssetFinderSetting.s.displayAtlasName,\n                AssetFinderSetting.s.showUsedByClassed,\n                    window,\n                    true\n                )\n            );\n\n            Texture tex = AssetDatabase.GetCachedIcon(rf.asset.assetPath);\n            if (tex == null) return;\n\n            Rect drawR = r;\n            drawR.x += drawR.width; // (groupDrawer.TreeNoScroll() ? 60f : 70f) ;\n            drawR.width = 40f;\n            drawR.y += 1;\n            drawR.height -= 2;\n\n            if (GUI.Button(drawR, \"Use\", EditorStyles.miniButton))\n            {\n                if (AssetFinderExport.IsMergeProcessing)\n                {\n                    AssetFinderLOG.LogWarning(\"Previous merge is processing\");\n                } \n                else\n                {\n                    int index = rf.index;\n                    Selection.objects = list.Where(x => x.index == index)\n                        .Select(x => AssetFinderUnity.LoadAssetAtPath<Object>(x.asset.assetPath)).ToArray();\n                    AssetFinderExport.MergeDuplicate(rf.asset.guid);\n                }\n            }\n\n            if (rf.asset.UsageCount() > 0) return;\n\n            drawR.x -= 25;\n            drawR.width = 20;\n            if (wasPreDelete(guid))\n            {\n                Color col = GUI.color;\n                GUI.color = Color.red;\n                if (GUI.Button(drawR, \"X\", EditorStyles.miniButton))\n                {\n                    guidPressDelete = null;\n                    AssetDatabase.DeleteAsset(rf.asset.assetPath);\n                }\n\n                GUI.color = col;\n                window.WillRepaint = true;\n            } \n            else\n            {\n                if (GUI.Button(drawR, \"X\", EditorStyles.miniButton))\n                {\n                    guidPressDelete = guid;\n                    TimePressDelete = Time.realtimeSinceStartup;\n                    window.WillRepaint = true;\n                }\n            }\n        }\n\n        private bool wasPreDelete(string guid)\n        {\n            if (guidPressDelete == null || guid != guidPressDelete) return false;\n\n            if (Time.realtimeSinceStartup - TimePressDelete < TimeDelayDelete) return true;\n\n            guidPressDelete = null;\n            return false;\n        }\n\n        private void DrawGroup(Rect r, string label, int childCount)\n        {\n            AssetFinderAsset asset = dicIndex[label][0].asset;\n\n            Texture tex = AssetDatabase.GetCachedIcon(asset.assetPath);\n            Rect rect = r;\n\n            if (tex != null)\n            {\n                rect.width = 16f;\n                GUI.DrawTexture(rect, tex);\n            }\n\n            rect = r;\n            rect.xMin += 16f;\n            GUI.Label(rect, asset.assetName, EditorStyles.boldLabel);\n\n            rect = r;\n            rect.xMin += rect.width - 50f;\n            GUI.Label(rect, AssetFinderHelper.GetfileSizeString(asset.fileSize), EditorStyles.miniLabel);\n\n            rect = r;\n            rect.xMin += rect.width - 100f;\n            GUI.Label(rect, childCount.ToString(), EditorStyles.miniLabel);\n            // Removed: status/progress/queue UI\n        }\n\n        public void Reset(List<List<string>> assetList)\n        {\n            progressState = ProgressState.Scanning;\n            groupVerificationStatus.Clear();\n            groupVerificationProgress.Clear();\n            groupVerificationOrder.Clear();\n            \n            fc.Reset(assetList, OnUpdateView, RefreshView);\n        }\n\n        private void OnUpdateView(List<List<string>> assetList)\n        {\n            // This is called during verification to update the view with current results\n            if (assetList != null)\n            {\n                cacheAssetList = assetList;\n                dirty = true;\n                window.WillRepaint = true;\n            }\n        }\n\n        public bool isExclueAnyItem()\n        {\n            return excludeCount > 0 || scanExcludeByTypeCount > 0;\n        }\n\n        public bool isExclueAnyItemByIgnoreFolder()\n        {\n            return scanExcludeByIgnoreCount > 0;\n        }\n\n        private void RefreshView(List<List<string>> assetList)\n        {\n            cacheAssetList = assetList;\n            dirty = false;\n            list = new List<AssetFinderRef>();\n            refs = new Dictionary<string, AssetFinderRef>();\n            dicIndex = new Dictionary<string, List<AssetFinderRef>>();\n            if (assetList == null) return;\n\n            int minScore = searchTerm.Length;\n            string term1 = searchTerm;\n            if (!caseSensitive) term1 = term1.ToLower();\n\n            string term2 = term1.Replace(\" \", string.Empty);\n            excludeCount = 0;\n\n            for (var i = 0; i < assetList.Count; i++)\n            {\n                var lst = new List<AssetFinderRef>();\n                for (var j = 0; j < assetList[i].Count; j++)\n                {\n                    string path = assetList[i][j];\n                    if (!path.StartsWith(\"Assets/\"))\n                    {\n                        AssetFinderLOG.LogWarning(\"Ignore asset: \" + path);\n                        continue;\n                    }\n\n                    string guid = AssetDatabase.AssetPathToGUID(path);\n                    if (string.IsNullOrEmpty(guid)) continue;\n\n                    if (refs.ContainsKey(guid)) continue;\n\n                    AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                    if (asset == null) continue;\n                    if (!asset.assetPath.StartsWith(\"Assets/\")) continue; // ignore builtin, packages, ...\n\n                    var fr2 = new AssetFinderRef(i, 0, asset, null);\n\n                    if (AssetFinderSetting.IsTypeExcluded(fr2.type))\n                    {\n                        excludeCount++;\n                        continue; //skip this one\n                    }\n\n                    if (string.IsNullOrEmpty(searchTerm))\n                    {\n                        fr2.matchingScore = 0;\n                        list.Add(fr2);\n                        lst.Add(fr2);\n                        refs.Add(guid, fr2);\n                        continue;\n                    }\n\n                    //calculate matching score\n                    string name1 = fr2.asset.assetName;\n                    if (!caseSensitive) name1 = name1.ToLower();\n\n                    string name2 = name1.Replace(\" \", string.Empty);\n\n                    int score1 = AssetFinderUnity.StringMatch(term1, name1);\n                    int score2 = AssetFinderUnity.StringMatch(term2, name2);\n\n                    fr2.matchingScore = Mathf.Max(score1, score2);\n                    if (fr2.matchingScore > minScore)\n                    {\n                        list.Add(fr2);\n                        lst.Add(fr2);\n                        refs.Add(guid, fr2);\n                    }\n                }\n\n                dicIndex.Add(i.ToString(), lst);\n                \n                // Initialize verification status for the group\n                if (isSignatureScanComplete)\n                {\n                    groupVerificationStatus[i.ToString()] = \"Pending\";\n                }\n            }\n\n            ResetGroup();\n        }\n\n        private void ResetGroup()\n        {\n            groupDrawer.Reset(list,\n                rf => rf.asset.guid\n                , GetGroup, SortGroup);\n            if (window != null) window.Repaint();\n        }\n\n        private string GetGroup(AssetFinderRef rf)\n        {\n            return rf.index.ToString();\n        }\n\n        private void SortGroup(List<string> groups)\n        {\n            // Sort by verification status, then by size\n            if (isSignatureScanComplete)\n            {\n                groups.Sort((a, b) => {\n                    // First check if either is currently verifying\n                    if (groupVerificationStatus.ContainsKey(a) && groupVerificationStatus[a] == \"Verifying\")\n                        return -1;\n                    if (groupVerificationStatus.ContainsKey(b) && groupVerificationStatus[b] == \"Verifying\")\n                        return 1;\n                    \n                    // Then check if verified\n                    bool aVerified = groupVerificationStatus.ContainsKey(a) && groupVerificationStatus[a] == \"Verified\";\n                    bool bVerified = groupVerificationStatus.ContainsKey(b) && groupVerificationStatus[b] == \"Verified\";\n                    if (aVerified && !bVerified) return -1;\n                    if (!aVerified && bVerified) return 1;\n                    \n                    // Then check queue position\n                    if (groupVerificationOrder.ContainsKey(a) && groupVerificationOrder.ContainsKey(b))\n                        return groupVerificationOrder[a].CompareTo(groupVerificationOrder[b]);\n                    \n                    // Default to standard order\n                    return a.CompareTo(b);\n                });\n            }\n        }\n\n        public void SetDirty()\n        {\n            dirty = true;\n        }\n\n        public void RefreshSort()\n        {\n            if (groupDrawer.hasValidTree)\n            {\n                SortGroup(groupDrawer.tree.rootItem.children.Select(item => item.id).ToList());\n                groupDrawer.Reset(list,\n                    rf => rf.asset.guid,\n                    GetGroup, SortGroup);\n                if (window != null) window.Repaint();\n            }\n        }\n\n        private void DrawHeader()\n        {\n            string text = groupDrawer.hasValidTree ? \"Rescan\" : \"Scan\";\n\n            EditorGUILayout.BeginHorizontal();\n            if (GUILayout.Button(text))\n            {\n                OnCacheReady();\n            }\n            // Removed: Refresh Sort button\n            EditorGUILayout.EndHorizontal();\n            // Removed: bottom status text\n        }\n\n        private void OnCacheReady()\n        {\n            scanExcludeByTypeCount = 0;\n            Reset(AssetFinderCache.Api.ScanSimilar(IgnoreTypeWhenScan, IgnoreFolderWhenScan));\n            AssetFinderCache.onReady -= OnCacheReady;\n        }\n\n        private void IgnoreTypeWhenScan()\n        {\n            scanExcludeByTypeCount++;\n        }\n\n        private void IgnoreFolderWhenScan()\n        {\n            scanExcludeByIgnoreCount++;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderDuplicateTree2.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f858ea142423a864caf1f7888f216d13\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderFileCompare.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderFileCompare\n    {\n        public static HashSet<AssetFinderChunk> HashChunksNotComplete;\n        internal static int streamClosedCount;\n        private List<List<string>> cacheList;\n        public List<AssetFinderHead> deads = new List<AssetFinderHead>();\n        public List<AssetFinderHead> heads = new List<AssetFinderHead>();\n\n        public int nChunks;\n        public int nChunks2;\n        public int nScaned;\n        public Action<List<List<string>>> OnCompareComplete;\n        public Action<List<List<string>>> OnCompareUpdate;\n\n        // Verification tracking\n        private Dictionary<string, float> verificationProgress = new Dictionary<string, float>();\n        private Dictionary<string, int> verificationOrder = new Dictionary<string, int>();\n        private Queue<string> verificationQueue = new Queue<string>();\n        private string currentlyVerifying = null;\n        private bool signatureScanComplete = false;\n\n        public void Reset(List<List<string>> list, Action<List<List<string>>> onUpdate, Action<List<List<string>>> onComplete)\n        {\n            nChunks = 0;\n            nScaned = 0;\n            nChunks2 = 0;\n\n            HashChunksNotComplete = new HashSet<AssetFinderChunk>();\n\n            if (heads.Count > 0)\n            {\n                for (var i = 0; i < heads.Count; i++)\n                {\n                    heads[i].CloseChunk();\n                }\n            }\n\n            deads.Clear();\n            heads.Clear();\n            verificationProgress.Clear();\n            verificationOrder.Clear();\n            verificationQueue.Clear();\n            currentlyVerifying = null;\n            signatureScanComplete = true; // Since we're using fileInfoHash, signatures are already computed\n\n            OnCompareUpdate = onUpdate;\n            OnCompareComplete = onComplete;\n            \n            if (list == null || list.Count <= 0)\n            {\n                OnCompareComplete(new List<List<string>>());\n                return;\n            }\n\n            cacheList = list;\n\n            // Sort groups by file size (smallest first for quicker processing)\n            cacheList.Sort((a, b) => \n            {\n                long sizeA = new FileInfo(a[0]).Length;\n                long sizeB = new FileInfo(b[0]).Length;\n                return sizeA.CompareTo(sizeB);\n            });\n            \n            // Setup verification queue\n            PrepareVerificationQueue();\n        }\n        \n        private void PrepareVerificationQueue()\n        {\n            // Create verification queue\n            for (int i = 0; i < cacheList.Count; i++)\n            {\n                string groupKey = \"Group-\" + i;\n                verificationQueue.Enqueue(groupKey);\n                verificationOrder[groupKey] = i + 1;\n                verificationProgress[groupKey] = 0f;\n            }\n            \n            // Trigger initial update with hash-based results\n            OnCompareUpdate?.Invoke(cacheList);\n            \n            // Start verification\n            if (verificationQueue.Count > 0)\n            {\n                StartNextVerification();\n            }\n            else\n            {\n                OnCompareComplete?.Invoke(new List<List<string>>());\n            }\n        }\n        \n        private void StartNextVerification()\n        {\n            if (verificationQueue.Count > 0)\n            {\n                currentlyVerifying = verificationQueue.Dequeue();\n                \n                // Use existing byte-by-byte verification\n                AddHead(cacheList[cacheList.Count - 1]);\n                cacheList.RemoveAt(cacheList.Count - 1);\n                \n                EditorApplication.update -= ReadChunkAsync;\n                EditorApplication.update += ReadChunkAsync;\n            }\n            else\n            {\n                // All verifications complete\n                currentlyVerifying = null;\n                OnCompareComplete?.Invoke(deads.Select(item => item.GetFiles()).ToList());\n            }\n        }\n        \n        public void PrioritizeGroup(string groupKey)\n        {\n            if (verificationQueue.Contains(groupKey))\n            {\n                // Remove from the queue\n                List<string> newQueue = verificationQueue.Where(k => k != groupKey).ToList();\n                verificationQueue.Clear();\n                \n                // Add the prioritized group at the front\n                verificationQueue.Enqueue(groupKey);\n                \n                // Add the rest back\n                foreach (string key in newQueue)\n                {\n                    verificationQueue.Enqueue(key);\n                }\n                \n                // Update order numbers\n                int position = 1;\n                foreach (string key in verificationQueue)\n                {\n                    verificationOrder[key] = position++;\n                }\n            }\n        }\n        \n        public Dictionary<string, float> GetVerificationProgress()\n        {\n            return verificationProgress;\n        }\n        \n        public Dictionary<string, int> GetVerificationOrder()\n        {\n            return verificationOrder;\n        }\n        \n        public string GetCurrentlyVerifying()\n        {\n            return currentlyVerifying;\n        }\n        \n        public bool IsSignatureScanComplete()\n        {\n            return signatureScanComplete;\n        }\n\n        public AssetFinderFileCompare AddHead(List<string> files)\n        {\n            if (files.Count < 2) Debug.LogWarning(\"Something wrong ! head should not contains < 2 elements\");\n\n            var chunkList = new List<AssetFinderChunk>();\n            for (var i = 0; i < files.Count; i++)\n            {\n                chunkList.Add(new AssetFinderChunk\n                {\n                    file = files[i],\n                    buffer = new byte[AssetFinderHead.chunkSize]\n                });\n            }\n\n            var file = new FileInfo(files[0]);\n            int nChunk = Mathf.CeilToInt(file.Length / (float)AssetFinderHead.chunkSize);\n\n            heads.Add(new AssetFinderHead\n            {\n                fileSize = file.Length,\n                currentChunk = 0,\n                nChunk = nChunk,\n                chunkList = chunkList,\n                groupKey = currentlyVerifying\n            });\n\n            nChunks += nChunk;\n\n            return this;\n        }\n\n        private void ReadChunkAsync()\n        {\n            bool alive = ReadChunk();\n            if (alive) \n            {\n                // Update verification progress\n                if (currentlyVerifying != null && nChunks > 0)\n                {\n                    verificationProgress[currentlyVerifying] = (float)nScaned / nChunks;\n                }\n                return;\n            }\n\n            var update = false;\n            for (int i = heads.Count - 1; i >= 0; i--)\n            {\n                AssetFinderHead h = heads[i];\n                if (!h.isDead) continue;\n\n                h.CloseChunk();\n                heads.RemoveAt(i);\n                if (h.chunkList.Count > 1)\n                {\n                    update = true;\n                    deads.Add(h);\n                }\n            }\n\n            if (update) Trigger(OnCompareUpdate);\n\n            // Set verification as complete for current group\n            if (currentlyVerifying != null)\n            {\n                verificationProgress[currentlyVerifying] = 1f;\n            }\n\n            if (cacheList.Count == 0)\n            {\n                foreach (AssetFinderChunk item in HashChunksNotComplete)\n                {\n                    if (item.stream == null || !item.stream.CanRead) continue;\n                    item.stream.Close();\n                    item.stream = null;\n                }\n\n                HashChunksNotComplete.Clear();\n                nScaned = nChunks;\n                EditorApplication.update -= ReadChunkAsync;\n                \n                // Verification complete, final callback\n                Trigger(OnCompareComplete);\n            }\n            else\n            {\n                // Continue with next group\n                StartNextVerification();\n            }\n        }\n\n        private void Trigger(Action<List<List<string>>> cb)\n        {\n            if (cb == null) return;\n\n            List<List<string>> list = deads.Select(item => item.GetFiles()).ToList();\n            cb(list);\n        }\n\n        private bool ReadChunk()\n        {\n            var alive = false;\n\n            for (var i = 0; i < heads.Count; i++)\n            {\n                AssetFinderHead h = heads[i];\n                if (h.isDead)\n                {\n                    continue;\n                }\n\n                nScaned++;\n                alive = true;\n                h.ReadChunk();\n                h.CompareChunk(heads);\n                break;\n            }\n\n            return alive;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderFileCompare.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1fcea19945e771a46ad57540490f9275\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderHead.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderHead\n    {\n        public const int chunkSize = 10240;\n\n        public List<AssetFinderChunk> chunkList;\n        public int currentChunk;\n        public long fileSize;\n        public int nChunk;\n        public int size; //last stream read size\n        public string groupKey; // For tracking group identity in verification queue\n\n        public bool isDead => currentChunk == nChunk || chunkList.Count == 1;\n\n        public List<string> GetFiles()\n        {\n            return chunkList.Select(item => item.file).ToList();\n        }\n\n        public void AddToDict(byte b, AssetFinderChunk chunk, Dictionary<byte, List<AssetFinderChunk>> dict)\n        {\n            List<AssetFinderChunk> list;\n            if (!dict.TryGetValue(b, out list))\n            {\n                list = new List<AssetFinderChunk>();\n                dict.Add(b, list);\n            }\n\n            list.Add(chunk);\n        }\n\n        public void CloseChunk()\n        {\n            for (var i = 0; i < chunkList.Count; i++)\n            {\n                AssetFinderFileCompare.streamClosedCount++;\n\n                if (chunkList[i].stream != null)\n                {\n                    chunkList[i].stream.Close();\n                    chunkList[i].stream = null;\n                }\n            }\n        }\n\n        public void ReadChunk()\n        {\n            if (currentChunk == nChunk)\n            {\n                AssetFinderLOG.LogWarning(\"Something wrong, should dead <\" + isDead + \">\");\n                return;\n            }\n\n            int from = currentChunk * chunkSize;\n            size = (int)Mathf.Min(fileSize - from, chunkSize);\n\n            for (var i = 0; i < chunkList.Count; i++)\n            {\n                AssetFinderChunk chunk = chunkList[i];\n                if (chunk.streamError) continue;\n                chunk.size = size;\n\n                if (chunk.streamInited == false)\n                {\n                    chunk.streamInited = true;\n\n                    try\n                    {\n                        chunk.stream = new FileStream(chunk.file, FileMode.Open, FileAccess.Read);\n                    }\n                    catch\n                    {\n                        chunk.streamError = true;\n                        if (chunk.stream != null) // just to make sure we close the stream\n                        {\n                            chunk.stream.Close();\n                            chunk.stream = null;\n                        }\n                    }\n\n                    if (chunk.stream == null)\n                    {\n                        chunk.streamError = true;\n                        continue;\n                    }\n                }\n\n                try\n                {\n                    chunk.stream.Seek(from, SeekOrigin.Begin);\n                    chunk.stream.Read(chunk.buffer, 0, size);\n                } \n                catch (Exception e)\n                {\n                    AssetFinderLOG.LogWarning(e + \"\\n\" + chunk.file);\n\n                    chunk.streamError = true;\n                    chunk.stream.Close();\n                }\n            }\n\n            // clean up dead chunks\n            for (int i = chunkList.Count - 1; i >= 0; i--)\n            {\n                if (chunkList[i].streamError) chunkList.RemoveAt(i);\n            }\n\n            if (chunkList.Count == 1) Debug.LogWarning(\"No more chunk in list\");\n\n            currentChunk++;\n        }\n\n        public void CompareChunk(List<AssetFinderHead> heads)\n        {\n            int idx = chunkList.Count;\n            byte[] buffer = chunkList[idx - 1].buffer;\n\n            while (--idx >= 0)\n            {\n                AssetFinderChunk chunk = chunkList[idx];\n                int diff = FirstDifferentIndex(buffer, chunk.buffer, size);\n                if (diff == -1) continue;\n\n                byte v = buffer[diff];\n\n                var d = new Dictionary<byte, List<AssetFinderChunk>>(); //new heads\n                chunkList.RemoveAt(idx);\n                AssetFinderFileCompare.HashChunksNotComplete.Add(chunk);\n\n                AddToDict(chunk.buffer[diff], chunk, d);\n\n                for (int j = idx - 1; j >= 0; j--)\n                {\n                    AssetFinderChunk tChunk = chunkList[j];\n                    byte tValue = tChunk.buffer[diff];\n                    if (tValue == v) continue;\n\n                    idx--;\n                    AssetFinderFileCompare.HashChunksNotComplete.Add(tChunk);\n                    chunkList.RemoveAt(j);\n                    AddToDict(tChunk.buffer[diff], tChunk, d);\n                }\n\n                foreach (KeyValuePair<byte, List<AssetFinderChunk>> item in d)\n                {\n                    List<AssetFinderChunk> list = item.Value;\n                    if (list.Count == 1)\n                    {\n                        if (list[0].stream != null) list[0].stream.Close();\n                    } \n                    else if (list.Count > 1) // 1 : dead head\n                    {\n                        heads.Add(new AssetFinderHead\n                        {\n                            nChunk = nChunk,\n                            fileSize = fileSize,\n                            currentChunk = currentChunk - 1,\n                            chunkList = list,\n                            groupKey = groupKey // Propagate the groupKey to new heads\n                        });\n                    }\n                }\n            }\n        }\n\n        internal static int FirstDifferentIndex(byte[] arr1, byte[] arr2, int maxIndex)\n        {\n            for (var i = 0; i < maxIndex; i++)\n            {\n                if (arr1[i] != arr2[i]) return i;\n            }\n\n            return -1;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate/AssetFinderHead.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2bfaaba7291e7244d984c18caaa91464\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Duplicate.meta",
    "content": "fileFormatVersion: 2\nguid: b5e941cf0fab44ba90c39a055cd2602e\ntimeCreated: 1747080908"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderExtension.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class GUIExtension\n    {\n        internal static bool drawDebug = false;\n        internal static readonly float debugAlpha = 0.02f;\n        internal static int debugCount;\n        internal static readonly Color[] debugColors =\n        {\n            Color.cyan.Alpha(debugAlpha),\n            Color.blue.Alpha(debugAlpha),\n            Color.green.Alpha(debugAlpha),\n            Color.yellow.Alpha(debugAlpha),\n            Color.magenta.Alpha(debugAlpha),\n            Color.red.Alpha(debugAlpha),\n            Color.white.Alpha(debugAlpha)\n        };\n\n#if AssetFinderDEV\n        [MenuItem(\"Window/FR2/Toggle Draw Debug\")]\n        internal static void ToggleDrawDebug()\n        {\n            drawDebug = !drawDebug;\n        }\n#endif\n\n\n\n        internal static bool isRepaint => Event.current.type == EventType.Repaint;\n        internal static bool isMouse => Event.current.isMouse;\n        internal static bool isLayout => Event.current.type == EventType.Layout;\n\n        public static Rect DrawOverlayDebug(this Rect rect, float alpha = 0.1f)\n        {\n            Color saved = GUI.color;\n            GUI.color = debugColors[debugCount++ % debugColors.Length];\n            {\n                GUI.DrawTexture(rect, Texture2D.whiteTexture, ScaleMode.StretchToFill);\n            }\n            GUI.color = saved;\n            return rect;\n        }\n\n        public static Rect LFoldout(this Rect rect, ref bool isOpen, bool drawCondition)\n        {\n            var (iconRect, flexRect) = rect.ExtractLeft();\n            if (!drawCondition) return flexRect;\n\n            isOpen = EditorGUI.Foldout(iconRect, isOpen, GUIContent.none);\n            if (drawDebug) DrawOverlayDebug(iconRect.Move(0, -2f));\n            return flexRect;\n        }\n\n        private static Rect DrawIcon(Rect rect, Texture icon, float w, bool left, bool drawCondition)\n        {\n            if (!drawCondition) return rect;\n            \n\n            var (iconRect, flexRect) = left ? rect.ExtractLeft(w) : rect.ExtractRight(w);\n            if ((icon != null) && isRepaint) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit);\n            if (drawDebug) DrawOverlayDebug(iconRect);\n            return flexRect;\n        }\n\n\n        private static Rect DrawLabel(Rect rect, GUIContent content, GUIStyle style, Color? color, bool left, bool drawCondition, float yOffset = 0)\n        {\n            if (content == null || content == GUIContent.none || !drawCondition) return rect;\n            float w = style.CalcSize(content).x;\n            \n            var (labelRect, flexRect) = left ? rect.ExtractLeft(w) : rect.ExtractRight(w);\n            if (drawDebug) DrawOverlayDebug(labelRect);\n            if (!isRepaint) return flexRect;\n\n            Color c = GUI.color;\n            if (color != null) GUI.color = color.Value;\n            {\n                GUI.Label(labelRect.Move(0f, yOffset), content, style);\n            }\n            GUI.color = c;\n            return flexRect;\n        }\n\n        public static Rect LColumn(this Rect rect, ref float columnW, Func<Rect, Rect> drawer)\n        {\n            var (lRect, flex) = rect.ExtractLeft(columnW);\n            if (drawer == null) return flex;\n\n            Rect padRect = drawer(lRect);\n            \n\n            if (padRect.width < 0f) columnW -= padRect.width;\n            return flex;\n        }\n\n        public static Rect RColumn(this Rect rect, ref float columnW, Func<Rect, Rect> drawer)\n        {\n            var (lRect, flex) = rect.ExtractRight(columnW);\n            if (drawer == null) return flex;\n\n            Rect padRect = drawer(lRect);\n            if (padRect.width < 0f) columnW -= padRect.width;\n            return flex;\n        }\n\n\n\n        // TAB\n        public static Rect LColumnAlign(this Rect rect, ref float columnX)\n        {\n            if (isLayout)\n            {\n                columnX = 0;\n                return rect;\n            }\n\n            columnX = Mathf.Max(rect.x, columnX);\n            rect.xMin = columnX;\n\n            return rect;\n        }\n\n        public static Rect RColumnAlign(this Rect rect, ref float columnX, string name)\n        {\n            if (rect.xMax <= 0)\n            {\n                columnX = -1;\n                return rect;\n            }\n\n            if (columnX < 0 || rect.xMax < columnX)\n            {\n                columnX = rect.xMax;\n                \n            } else\n            {\n                rect.xMax = columnX;\n            }\n\n            return rect;\n        }\n\n        public static Rect LDrawIcon(this Rect rect, Texture icon, float w = 16f, bool drawCondition = true)\n        {\n            return DrawIcon(rect, icon, w, true, drawCondition);\n        }\n\n        public static Rect RDrawIcon(this Rect rect, Texture icon, float w = 16f, bool drawCondition = true)\n        {\n            return DrawIcon(rect, icon, w, false, drawCondition);\n        }\n\n        // Label\n        public static Rect LDrawLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true)\n        {\n            return DrawLabel(rect, AssetFinderGUIContent.FromString(label), EditorStyles.label, color, true, drawCondition);\n        }\n\n        public static Rect RDrawLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true)\n        {\n            return DrawLabel(rect, AssetFinderGUIContent.FromString(label), EditorStyles.label, color, false, drawCondition);\n        }\n\n\n        public static Rect LDrawMiniLabel(this Rect rect, GUIContent label, Color? color = null, bool drawCondition = true)\n        {\n            return DrawLabel(rect, label, EditorStyles.miniLabel, color, true, drawCondition, 1f);\n        }\n\n        public static Rect LDrawMiniLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true)\n        {\n            return LDrawMiniLabel(rect, AssetFinderGUIContent.FromString(label), color, drawCondition);\n        }\n\n        public static Rect RDrawMiniLabel(this Rect rect, GUIContent label, Color? color = null, bool drawCondition = true)\n        {\n            return DrawLabel(rect, label, EditorStyles.miniLabel, color, false, drawCondition, 1f);\n        }\n\n        public static Rect RDrawMiniLabel(this Rect rect, string label, Color? color = null, bool drawCondition = true)\n        {\n            return RDrawMiniLabel(rect, AssetFinderGUIContent.FromString(label), color, drawCondition);\n        }\n\n        public static Rect LDrawLabel(this Rect rect, GUIContent content, GUIStyle style = null, Color? color = null, bool drawCondition = true)\n        {\n            if (content == null || content == GUIContent.none || !drawCondition) return rect;\n\n            if (style == null) style = EditorStyles.label;\n            float w = style.CalcSize(content).x;\n            \n            var (labelRect, flexRect) = rect.ExtractLeft(w);\n            if (drawDebug) DrawOverlayDebug(labelRect);\n            if (!isRepaint) return flexRect;\n\n            Color c = GUI.color;\n            if (color != null) GUI.color = color.Value;\n            {\n                GUI.Label(labelRect, content, style);\n            }\n            GUI.color = c;\n            return flexRect;\n        }\n\n        public static Rect RDrawLabel(this Rect rect, GUIContent content, GUIStyle style = null, Color? color = null, bool drawCondition = true)\n        {\n            if (content == null || content == GUIContent.none || !drawCondition) return rect;\n\n            if (style == null) style = EditorStyles.label;\n            float w = style.CalcSize(content).x;\n            \n            var (labelRect, flexRect) = rect.ExtractRight(w);\n            if (drawDebug) DrawOverlayDebug(labelRect);\n            if (!isRepaint) return flexRect;\n\n            Color c = GUI.color;\n            if (color != null) GUI.color = color.Value;\n            {\n                GUI.Label(labelRect, content, style);\n            }\n            GUI.color = c;\n            return flexRect;\n        }\n\n\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderExtension.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ab1834f1ebc4a3fb6bb0a8d6835c370\ntimeCreated: 1725377102"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderHelper.cs",
    "content": "using System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.SceneManagement;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class AssetFinderHelper\n    {\n\n\n        public static IEnumerable<GameObject> getAllObjsInCurScene()\n        {\n            return GameObjectExtensions.GetAllGameObjectsInCurrentScenes();\n        }\n\n        private static IEnumerable<GameObject> GetGameObjectsInScene(Scene scene)\n        {\n            var rootObjects = new List<GameObject>();\n            scene.GetRootGameObjects(rootObjects);\n\n            // iterate root objects and do something\n            for (var i = 0; i < rootObjects.Count; ++i)\n            {\n                GameObject gameObject = rootObjects[i];\n\n                foreach (GameObject item in getAllChild(gameObject))\n                {\n                    yield return item;\n                }\n\n                yield return gameObject;\n            }\n        }\n\n        public static IEnumerable<GameObject> getAllChild(GameObject target)\n        {\n            return target.GetAllChildren(false);\n        }\n\n        public static IEnumerable<Object> GetAllRefObjects(GameObject obj)\n        {\n            return obj.GetAllObjectReferences();\n        }\n\n        public static int StringMatch(string pattern, string input)\n        {\n            if (string.IsNullOrEmpty(pattern) || string.IsNullOrEmpty(input)) return 0;\n            \n            pattern = pattern.ToLower();\n            input = input.ToLower();\n            \n            if (input.Contains(pattern)) return 100;\n            \n            int score = 0;\n            int patternIdx = 0;\n            \n            for (int i = 0; i < input.Length && patternIdx < pattern.Length; i++)\n            {\n                if (input[i] == pattern[patternIdx])\n                {\n                    score += 10;\n                    patternIdx++;\n                }\n            }\n            \n            return patternIdx == pattern.Length ? score : 0;\n        }\n\n        public static string GetfileSizeString(long fileSize)\n        {\n            if (fileSize < 1024) return fileSize + \" B\";\n            if (fileSize < 1024 * 1024) return (fileSize / 1024f).ToString(\"F1\") + \" KB\";\n            if (fileSize < 1024 * 1024 * 1024) return (fileSize / (1024f * 1024f)).ToString(\"F1\") + \" MB\";\n            return (fileSize / (1024f * 1024f * 1024f)).ToString(\"F1\") + \" GB\";\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderHelper.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8828b643803591948bdcb8e6e9d898c3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderUnity.cs",
    "content": "#if UNITY_5_3_OR_NEWER\n#define UNITY_4_3_OR_NEWER\n#define UNITY_4_4_OR_NEWER\n#define UNITY_4_5_OR_NEWER\n#define UNITY_4_6_OR_NEWER\n#define UNITY_4_7_OR_NEWER\n#define UNITY_5_0_OR_NEWER\n#define UNITY_5_1_OR_NEWER\n#define UNITY_5_2_OR_NEWER\n#else\n#if UNITY_5\n#define UNITY_4_3_OR_NEWER\n#define UNITY_4_4_OR_NEWER\n#define UNITY_4_5_OR_NEWER\n#define UNITY_4_6_OR_NEWER\n#define UNITY_4_7_OR_NEWER\n\t\n#if UNITY_5_0\n#define UNITY_5_0_OR_NEWER\n#elif UNITY_5_1\n#define UNITY_5_0_OR_NEWER\n#define UNITY_5_1_OR_NEWER\n#elif UNITY_5_2\n#define UNITY_5_0_OR_NEWER\n#define UNITY_5_1_OR_NEWER\n#define UNITY_5_2_OR_NEWER\n#endif\n#else\n#if UNITY_4_3\n#define UNITY_4_3_OR_NEWER\n#elif UNITY_4_4\n#define UNITY_4_3_OR_NEWER\n#define UNITY_4_4_OR_NEWER\n#elif UNITY_4_5\n#define UNITY_4_3_OR_NEWER\n#define UNITY_4_4_OR_NEWER\n#define UNITY_4_5_OR_NEWER\n#elif UNITY_4_6\n#define UNITY_4_3_OR_NEWER\n#define UNITY_4_4_OR_NEWER\n#define UNITY_4_5_OR_NEWER\n#define UNITY_4_6_OR_NEWER\n#elif UNITY_4_7\n#define UNITY_4_3_OR_NEWER\n#define UNITY_4_4_OR_NEWER\n#define UNITY_4_5_OR_NEWER\n#define UNITY_4_6_OR_NEWER\n#define UNITY_4_7_OR_NEWER\n#endif\n#endif\n#endif\n\n\n#if UNITY_5_3_OR_NEWER\n#define UNITY_SCENE_MANAGER\n#endif\n\n#if AssetFinderADDRESSABLE\nusing UnityEditor.AddressableAssets;\n#endif\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing UnityEditor;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\n#if UNITY_SCENE_MANAGER\nusing UnityEngine.SceneManagement;\nusing System.IO;\n#endif\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderUnity\n    {\n        internal static bool isEditorPlaying;\n        internal static bool isEditorUpdating;\n        internal static bool isEditorCompiling;\n        internal static bool isEditorPlayingOrWillChangePlaymode;\n\n        private static int highlightCounter = 0;\n\n        public static void RefreshEditorStatus()\n        {\n            isEditorPlaying = EditorApplication.isPlaying;\n            isEditorUpdating = EditorApplication.isUpdating;\n            isEditorCompiling = EditorApplication.isCompiling;\n            isEditorPlayingOrWillChangePlaymode = EditorApplication.isPlayingOrWillChangePlaymode;\n        }\n\n        public static HashSet<string> _Selection_AssetGUIDs;\n\n        public static bool StringStartsWith(string source, params string[] prefixes)\n        {\n            if (string.IsNullOrEmpty(source)) return false;\n            for (var i = 0; i < prefixes.Length; i++)\n            {\n                if (source.StartsWith(prefixes[i])) return true;\n            }\n\n            return false;\n        }\n\n        public static void SplitPath(string assetPath, out string assetName, out string assetExtension, out string assetFolder)\n        {\n            assetName = string.Empty;\n            assetFolder = string.Empty;\n            assetExtension = string.Empty;\n\n            if (string.IsNullOrEmpty(assetPath)) return;\n\n            assetExtension = Path.GetExtension(assetPath);\n            assetName = Path.GetFileNameWithoutExtension(assetPath);\n            int lastSlash = assetPath.LastIndexOf(\"/\", StringComparison.Ordinal) + 1;\n            assetFolder = assetPath.Substring(0, lastSlash);\n\n            // Debug.Log($\"{assetPath} --> \\n{assetName}\\n{assetExtension}\\n{assetFolder}\");\n        }\n\n        public static string[] Selection_AssetGUIDs\n        {\n            get\n            {\n#if UNITY_5_0_OR_NEWER\n                Object[] objs = Selection.objects;\n\n                _Selection_AssetGUIDs = new HashSet<string>();\n                foreach (Object item in objs)\n                {\n#if UNITY_2018_1_OR_NEWER\n                    {\n                        var guid = \"\";\n                        long fileid = -1;\n\n                        try\n                        { // missing references will cause null exception\n                            if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(item, out guid, out fileid)) _Selection_AssetGUIDs.Add(guid + \"/\" + fileid);\n\n                            //Debug.Log(\"guid: \" + guid + \"  fileID: \" + fileid);\n                        } catch { }\n\n                    }\n#else\n\t                {\n                    \tvar path = AssetDatabase.GetAssetPath(item);\n                        if (string.IsNullOrEmpty(path)) continue;\n                        var guid = AssetDatabase.AssetPathToGUID(path);\n                        System.Reflection.PropertyInfo inspectorModeInfo =\n                        typeof(SerializedObject).GetProperty(\"inspectorMode\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);\n\n                        SerializedObject serializedObject = new SerializedObject(item);\n                        inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);\n\n                        SerializedProperty localIdProp =\n                            serializedObject.FindProperty(\"m_LocalIdentfierInFile\");   //note the misspelling!\n\n                        var localId = localIdProp.longValue;\n                        if (localId <= 0)\n                        {\n                            localId = localIdProp.intValue;\n                        }\n                        if (localId <= 0)\n                        {\n                            continue;\n                        }\n                        if (!string.IsNullOrEmpty(guid)) _Selection_AssetGUIDs.Add(guid + \"/\" + localId);\n\t                }\n#endif\n\n                }\n\n\n                return Selection.assetGUIDs;\n#else\n\t\t\tvar mInfo =\n typeof(Selection).GetProperty(\"assetGUIDs\", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);\n\t\t\tif (mInfo != null){\n\t\t\t\treturn (string[]) mInfo.GetValue(null, null);\n\t\t\t}\n\t\t\tAssetFinderLOG.LogWarning(\"Unity changed ! Selection.assetGUIDs not found !\");\n\t\t    return new string[0];\n#endif\n            }\n        }\n\n        public static void PingAndHighlight(\n            Component component,\n            string propertyPath,\n            float glowSeconds = 5f)\n        {\n            if (component == null) return;\n            \n            // auto-lock\n            var window = EditorWindow.focusedWindow as AssetFinderWindowAll;\n            if (window != null) window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Scene);\n            \n            Selection.activeGameObject = component.gameObject;\n            ExpandPropertyPath(component, propertyPath);\n            SetEditorsExpanded(component);\n            \n            EditorApplication.delayCall += () =>\n            {\n                if (window != null) window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Scene);\n                Selection.activeGameObject = component.gameObject;\n                \n                EditorApplication.delayCall += () =>\n                {\n                    highlightCounter++;\n                    var currentHighlightId = highlightCounter;\n                    var success = TriggerHighlight(propertyPath);\n                    if (success)\n                    {\n                        StopHighlightAt(currentHighlightId, EditorApplication.timeSinceStartup + glowSeconds);\n                        return;\n                    }\n                    \n                    Debug.Log($\"Can not highlight property <{propertyPath}> in Inspector <{component.GetType().Name}>\\nThe Inspector might be locked or the property is hidden\\n\\n\");\n                };\n            };\n        }\n\n        private static bool TriggerHighlight(string propertyPath)\n        {\n            var result = false;\n            using (AssetFinderDev.NoLog)\n            {\n                result = Highlight(propertyPath);\n                if (!result) // Array?\n                {\n                    var path2 = propertyPath.Replace(\".Array.data[\", \"[\");\n                    result = Highlight(path2);\n                }\n                if (!result) result = Highlight(propertyPath.Split('.')[0]);\n            }\n            return result;\n        }\n        \n        private static bool Highlight(string propertyPath)\n        {\n            var  result = Highlighter.Highlight(\"Inspector\", propertyPath, HighlightSearchMode.Auto);\n            if (!result) result = Highlighter.Highlight(\"Inspector\", ObjectNames.NicifyVariableName(propertyPath), HighlightSearchMode.Auto);\n            return result;\n        }\n\n        private static void StopHighlightAt(int highlightId, double stopTime)\n        {\n            void Check()\n            {\n                if (highlightCounter > highlightId)\n                {\n                    EditorApplication.update -= Check;\n                    return;\n                }\n\n                if (EditorApplication.timeSinceStartup < stopTime) return;\n                Highlighter.Stop();\n                EditorApplication.update -= Check;\n            }\n            \n            EditorApplication.update += Check;\n        }\n        \n        private static void CollapseAllComponentsExcept(Component targetComponent)\n        {\n            if (targetComponent == null) return;\n            var gameObject = targetComponent.gameObject;\n            var allComponents = gameObject.GetComponents<Component>();\n            foreach (var comp in allComponents)\n            {\n                var expect = comp == targetComponent;\n                var before = InternalEditorUtility.GetIsInspectorExpanded(comp);\n                InternalEditorUtility.SetIsInspectorExpanded(comp, expect);\n                var after = InternalEditorUtility.GetIsInspectorExpanded(comp);\n\n                if (after != expect)\n                {\n                    Debug.LogWarning($\"comp: {comp.GetType().Name} |  before: {before} --> after: {InternalEditorUtility.GetIsInspectorExpanded(comp)} | expect: {expect}\");    \n                }\n            }\n        }\n\n        private static void DoExpand(Component c)\n        {\n            var tracker = ActiveEditorTracker.sharedTracker;\n            for (var i = 0; i < tracker.activeEditors.Length; i++)\n            {\n                var editor = tracker.activeEditors[i];\n                var isExpand = editor.target == c;\n                InternalEditorUtility.SetIsInspectorExpanded(editor.target, isExpand);\n                editor.serializedObject.ApplyModifiedProperties();\n                editor.Repaint();\n            }\n        }\n\n        private static void SetEditorsExpanded(Component c)\n        {\n            DoExpand(c);\n            Selection.activeGameObject = null;\n        }\n        \n        private static void SetEditorsExpanded2(Component c)\n        {\n            var tracker = ActiveEditorTracker.sharedTracker;\n            for (int i = 0; i < tracker.activeEditors.Length; i++)\n            {\n                var expanded = c == tracker.activeEditors[i].target;\n                tracker.SetVisible(i, expanded ? 1 : 0);\n            }\n            \n            var inspectorWindow = GetInspectorWindow();\n            if (inspectorWindow != null) inspectorWindow.Repaint();\n        }\n    \n        private static EditorWindow GetInspectorWindow()\n        {\n            System.Type inspectorType = typeof(EditorWindow).Assembly.GetType(\"UnityEditor.InspectorWindow\");\n            return EditorWindow.GetWindow(inspectorType);\n        }\n        \n        private static void ExpandPropertyPath(Component component, string propertyPath)\n        {\n            if (component == null) return;\n            var serializedObject = new SerializedObject(component);\n            serializedObject.Update();\n            var prop = serializedObject.GetIterator();\n            var deep = true;\n            while (prop.NextVisible(deep))\n            {\n                if (!propertyPath.Contains(prop.propertyPath))\n                {\n                    prop.isExpanded = false;\n                    deep = false;\n                    continue;\n                }\n                \n                prop.isExpanded = true;\n                deep = true;\n            }\n            serializedObject.ApplyModifiedPropertiesWithoutUndo();\n        }\n\n        private static readonly Lazy<Dictionary<int, string>> HashClassesNormalLazy =\n            new Lazy<Dictionary<int, string>>(() => new Dictionary<int, string>\n            {\n                { 1, \"UnityEngine.GameObject\" },\n                { 2, \"UnityEngine.Component\" },\n                { 4, \"UnityEngine.Transform\" },\n                { 8, \"UnityEngine.Behaviour\" },\n                { 12, \"UnityEngine.ParticleAnimator\" },\n                { 15, \"UnityEngine.EllipsoidParticleEmitter\" },\n                { 20, \"UnityEngine.Camera\" },\n                { 21, \"UnityEngine.Material\" },\n                { 23, \"UnityEngine.MeshRenderer\" },\n                { 25, \"UnityEngine.Renderer\" },\n                { 26, \"UnityEngine.ParticleRenderer\" },\n                { 27, \"UnityEngine.Texture\" },\n                { 28, \"UnityEngine.Texture2D\" },\n                { 33, \"UnityEngine.MeshFilter\" },\n                { 41, \"UnityEngine.OcclusionPortal\" },\n                { 43, \"UnityEngine.Mesh\" },\n                { 45, \"UnityEngine.Skybox\" },\n                { 47, \"UnityEngine.QualitySettings\" },\n                { 48, \"UnityEngine.Shader\" },\n                { 49, \"UnityEngine.TextAsset\" },\n                { 50, \"UnityEngine.Rigidbody2D\" },\n                { 53, \"UnityEngine.Collider2D\" },\n                { 54, \"UnityEngine.Rigidbody\" },\n                { 56, \"UnityEngine.Collider\" },\n                { 57, \"UnityEngine.Joint\" },\n                { 58, \"UnityEngine.CircleCollider2D\" },\n                { 59, \"UnityEngine.HingeJoint\" },\n                { 60, \"UnityEngine.PolygonCollider2D\" },\n                { 61, \"UnityEngine.BoxCollider2D\" },\n                { 62, \"UnityEngine.PhysicsMaterial2D\" },\n                { 64, \"UnityEngine.MeshCollider\" },\n                { 65, \"UnityEngine.BoxCollider\" },\n                { 68, \"UnityEngine.EdgeCollider2D\" },\n                { 72, \"UnityEngine.ComputeShader\" },\n                { 74, \"UnityEngine.AnimationClip\" },\n                { 75, \"UnityEngine.ConstantForce\" },\n                { 81, \"UnityEngine.AudioListener\" },\n                { 82, \"UnityEngine.AudioSource\" },\n                { 83, \"UnityEngine.AudioClip\" },\n                { 84, \"UnityEngine.RenderTexture\" },\n                { 87, \"UnityEngine.MeshParticleEmitter\" },\n                { 88, \"UnityEngine.ParticleEmitter\" },\n                { 89, \"UnityEngine.Cubemap\" },\n                { 90, \"Avatar\" },\n                { 92, \"UnityEngine.GUILayer\" },\n                { 93, \"UnityEngine.RuntimeAnimatorController\" },\n                { 95, \"UnityEngine.Animator\" },\n                { 96, \"UnityEngine.TrailRenderer\" },\n                { 102, \"UnityEngine.TextMesh\" },\n                { 104, \"UnityEngine.RenderSettings\" },\n                { 108, \"UnityEngine.Light\" },\n                { 111, \"UnityEngine.Animation\" },\n                { 114, \"UnityEngine.MonoBehaviour\" },\n                { 115, \"UnityEditor.MonoScript\" },\n                { 117, \"UnityEngine.Texture3D\" },\n                { 119, \"UnityEngine.Projector\" },\n                { 120, \"UnityEngine.LineRenderer\" },\n                { 121, \"UnityEngine.Flare\" },\n                { 123, \"UnityEngine.LensFlare\" },\n                { 124, \"UnityEngine.FlareLayer\" },\n                { 128, \"UnityEngine.Font\" },\n                { 129, \"UnityEditor.PlayerSettings\" },\n                { 131, \"UnityEngine.GUITexture\" },\n                { 132, \"UnityEngine.GUIText\" },\n                { 133, \"UnityEngine.GUIElement\" },\n                { 134, \"UnityEngine.PhysicMaterial\" },\n                { 135, \"UnityEngine.SphereCollider\" },\n                { 136, \"UnityEngine.CapsuleCollider\" },\n                { 137, \"UnityEngine.SkinnedMeshRenderer\" },\n                { 138, \"UnityEngine.FixedJoint\" },\n                { 142, \"UnityEngine.AssetBundle\" },\n                { 143, \"UnityEngine.CharacterController\" },\n                { 144, \"UnityEngine.CharacterJoint\" },\n                { 145, \"UnityEngine.SpringJoint\" },\n                { 146, \"UnityEngine.WheelCollider\" },\n                { 152, \"UnityEngine.MovieTexture\" },\n                { 153, \"UnityEngine.ConfigurableJoint\" },\n                { 154, \"UnityEngine.TerrainCollider\" },\n                { 156, \"UnityEngine.TerrainData\" },\n                { 157, \"UnityEngine.LightmapSettings\" },\n                { 158, \"UnityEngine.WebCamTexture\" },\n                { 159, \"UnityEditor.EditorSettings\" },\n                { 162, \"UnityEditor.EditorUserSettings\" },\n                { 164, \"UnityEngine.AudioReverbFilter\" },\n                { 165, \"UnityEngine.AudioHighPassFilter\" },\n                { 166, \"UnityEngine.AudioChorusFilter\" },\n                { 167, \"UnityEngine.AudioReverbZone\" },\n                { 168, \"UnityEngine.AudioEchoFilter\" },\n                { 169, \"UnityEngine.AudioLowPassFilter\" },\n                { 170, \"UnityEngine.AudioDistortionFilter\" },\n                { 171, \"UnityEngine.SparseTexture\" },\n                { 180, \"UnityEngine.AudioBehaviour\" },\n                { 182, \"UnityEngine.WindZone\" },\n                { 183, \"UnityEngine.Cloth\" },\n                { 192, \"UnityEngine.OcclusionArea\" },\n                { 193, \"UnityEngine.Tree\" },\n                { 198, \"UnityEngine.ParticleSystem\" },\n                { 199, \"UnityEngine.ParticleSystemRenderer\" },\n                { 200, \"UnityEngine.ShaderVariantCollection\" },\n                { 205, \"UnityEngine.LODGroup\" },\n                { 207, \"UnityEngine.Motion\" },\n                { 212, \"UnityEngine.SpriteRenderer\" },\n                { 213, \"UnityEngine.Sprite\" },\n                { 215, \"UnityEngine.ReflectionProbe\" },\n                { 218, \"UnityEngine.Terrain\" },\n                { 220, \"UnityEngine.LightProbeGroup\" },\n                { 221, \"UnityEngine.AnimatorOverrideController\" },\n                { 222, \"UnityEngine.CanvasRenderer\" },\n                { 223, \"UnityEngine.Canvas\" },\n                { 224, \"UnityEngine.RectTransform\" },\n                { 225, \"UnityEngine.CanvasGroup\" },\n                { 226, \"UnityEngine.BillboardAsset\" },\n                { 227, \"UnityEngine.BillboardRenderer\" },\n                { 229, \"UnityEngine.AnchoredJoint2D\" },\n                { 230, \"UnityEngine.Joint2D\" },\n                { 231, \"UnityEngine.SpringJoint2D\" },\n                { 232, \"UnityEngine.DistanceJoint2D\" },\n                { 233, \"UnityEngine.HingeJoint2D\" },\n                { 234, \"UnityEngine.SliderJoint2D\" },\n                { 235, \"UnityEngine.WheelJoint2D\" },\n                { 246, \"UnityEngine.PhysicsUpdateBehaviour2D\" },\n                { 247, \"UnityEngine.ConstantForce2D\" },\n                { 248, \"UnityEngine.Effector2D\" },\n                { 249, \"UnityEngine.AreaEffector2D\" },\n                { 250, \"UnityEngine.PointEffector2D\" },\n                { 251, \"UnityEngine.PlatformEffector2D\" },\n                { 252, \"UnityEngine.SurfaceEffector2D\" },\n                { 258, \"UnityEngine.LightProbes\" },\n                { 290, \"UnityEngine.AssetBundleManifest\" },\n                { 1003, \"UnityEditor.AssetImporter\" },\n                { 1004, \"UnityEditor.AssetDatabase\" },\n                { 1006, \"UnityEditor.TextureImporter\" },\n                { 1007, \"UnityEditor.ShaderImporter\" },\n                { 1011, \"UnityEngine.AvatarMask\" },\n                { 1020, \"UnityEditor.AudioImporter\" },\n                { 1029, \"UnityEditor.DefaultAsset\" },\n                { 1032, \"UnityEditor.SceneAsset\" },\n                { 1035, \"UnityEditor.MonoImporter\" },\n                { 1040, \"UnityEditor.ModelImporter\" },\n                { 1042, \"UnityEditor.TrueTypeFontImporter\" },\n                { 1044, \"UnityEditor.MovieImporter\" },\n                { 1045, \"UnityEditor.EditorBuildSettings\" },\n                { 1050, \"UnityEditor.PluginImporter\" },\n                { 1051, \"UnityEditor.EditorUserBuildSettings\" },\n                { 1105, \"UnityEditor.HumanTemplate\" },\n                { 1110, \"UnityEditor.SpeedTreeImporter\" },\n                { 1113, \"UnityEditor.LightmapParameters\" }\n            });\n\n        public static Dictionary<int, string> HashClassesNormal => HashClassesNormalLazy.Value;\n\n        //private static Texture2D _whiteTexture;\n        //public static Texture2D whiteTexture {\n        //\tget {\n        //\t\treturn EditorGUIUtility.whiteTexture;\n\n        //\t\t#if UNITY_5_0_OR_NEWER\n        //\t\treturn EditorGUIUtility.whiteTexture;\n        //\t\t#else\n        //\t\tif (_whiteTexture != null) return _whiteTexture;\n        //\t\t_whiteTexture = new Texture2D(1,1, TextureFormat.RGBA32, false);\n        //        _whiteTexture.SetPixel(0, 0, Color.white);\n        //\t\t_whiteTexture.hideFlags = HideFlags.DontSave;\n        //\t\treturn _whiteTexture;\n        //\t\t#endif\n        //\t}\n        //}\n\n        public static T LoadAssetAtPath<T>(string path) where T : Object\n        {\n#if UNITY_5_1_OR_NEWER\n            return AssetDatabase.LoadAssetAtPath<T>(path);\n#else\n\t\t\treturn (T)AssetDatabase.LoadAssetAtPath(path, typeof(T));\n#endif\n        }\n\n        public static void SetWindowTitle(EditorWindow window, string title)\n        {\n#if UNITY_5_1_OR_NEWER\n            window.titleContent = AssetFinderGUIContent.FromString(title);\n#else\n\t        window.title = title;\n#endif\n        }\n\n        public static void GetCompilingPhase(string path, out bool isPlugin, out bool isEditor)\n        {\n#if (UNITY_5_2_0 || UNITY_5_2_1) && !UNITY_5_2_OR_NEWER\n\t\t\tbool oldSystem = true;\n#else\n            var oldSystem = false;\n#endif\n\n            // ---- Old system: Editor for the plugin should be Plugins/Editor\n            if (oldSystem)\n            {\n                bool isPluginEditor = path.StartsWith(\"Assets/Plugins/Editor/\", StringComparison.Ordinal)\n                    || path.StartsWith(\"Assets/Standard Assets/Editor/\", StringComparison.Ordinal)\n                    || path.StartsWith(\"Assets/Pro Standard Assets/Editor/\",\n                        StringComparison.Ordinal);\n\n                if (isPluginEditor)\n                {\n                    isPlugin = true;\n                    isEditor = true;\n                    return;\n                }\n            }\n\n            isPlugin = path.StartsWith(\"Assets/Plugins/\", StringComparison.Ordinal)\n                || path.StartsWith(\"Assets/Standard Assets/\", StringComparison.Ordinal)\n                || path.StartsWith(\"Assets/Pro Standard Assets/\", StringComparison.Ordinal);\n\n            isEditor = oldSystem && isPlugin ? false : path.Contains(\"/Editor/\");\n        }\n\n        public static T LoadAssetWithGUID<T>(string guid) where T : Object\n        {\n            if (string.IsNullOrEmpty(guid)) return null;\n\n            string path = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(path)) return null;\n\n#if UNITY_5_1_OR_NEWER\n            return AssetDatabase.LoadAssetAtPath<T>(path);\n#else\n\t\t\treturn (T)AssetDatabase.LoadAssetAtPath(path, typeof(T));\n#endif\n        }\n\n        public static void UnloadUnusedAssets()\n        {\n#if UNITY_5_0_OR_NEWER\n            EditorUtility.UnloadUnusedAssetsImmediate();\n#else\n\t\t\tEditorUtility.UnloadUnusedAssets();\n#endif\n            Resources.UnloadUnusedAssets();\n        }\n\n        internal static int Epoch(DateTime time)\n        {\n            return (int)(time.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;\n        }\n\n        internal static bool DrawToggle(ref bool v, string label)\n        {\n            bool v1 = GUILayout.Toggle(v, label);\n            if (v1 != v)\n            {\n                v = v1;\n                return true;\n            }\n\n            return false;\n        }\n\n        internal static bool DrawToggleToolbar(ref bool v, string label, float width)\n        {\n            bool v1 = GUILayout.Toggle(v, label, EditorStyles.toolbarButton, GUILayout.Width(width));\n            if (v1 != v)\n            {\n                v = v1;\n                return true;\n            }\n\n            return false;\n        }\n\n        internal static bool DrawToggleToolbar(ref bool v, GUIContent icon, float width)\n        {\n            bool v1 = GUILayout.Toggle(v, icon, EditorStyles.toolbarButton, GUILayout.Width(width));\n            if (v1 != v)\n            {\n                v = v1;\n                return true;\n            }\n\n            return false;\n        }\n\n        public static string GetAddressable(string guid)\n        {\n#if AssetFinderADDRESSABLE\n\t\t\tvar aaSettings = AddressableAssetSettingsDefaultObject.GetSettings(true);\n\t\t\tvar entry = aaSettings.FindAssetEntry(guid);\n\t\t\treturn entry != null ? entry.address : string.Empty;\n#endif\n\n            return null;\n        }\n\n        internal static EditorWindow FindEditor(string className)\n        {\n            EditorWindow[] list = Resources.FindObjectsOfTypeAll<EditorWindow>();\n            foreach (EditorWindow item in list)\n            {\n                if (item.GetType().FullName == className) return item;\n            }\n\n            return null;\n        }\n\n        internal static void RepaintAllEditor(string className)\n        {\n            EditorWindow[] list = Resources.FindObjectsOfTypeAll<EditorWindow>();\n\n            foreach (EditorWindow item in list)\n            {\n#if AssetFinderDEV\n\t\t\tDebug.Log(item.GetType().FullName);\n#endif\n\n                if (item.GetType().FullName != className) continue;\n\n                item.Repaint();\n            }\n        }\n\n        internal static void RepaintProjectWindows()\n        {\n            RepaintAllEditor(\"UnityEditor.ProjectBrowser\");\n        }\n\n        internal static void RepaintFR2Windows()\n        {\n            RepaintAllEditor(\"vietlabs.fr2.AssetFinderWindow\");\n        }\n\n        internal static void ExportSelection()\n        {\n            Type packageExportT = null;\n\n            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())\n            {\n                packageExportT = assembly.GetType(\"UnityEditor.PackageExport\");\n                if (packageExportT != null) break;\n            }\n\n            if (packageExportT == null)\n            {\n                AssetFinderLOG.LogWarning(\"Export Package Error : UnityEditor.PackageExport not found !\");\n                return;\n            }\n\n            EditorWindow panel = EditorWindow.GetWindow(packageExportT, true, \"Exporting package\");\n#if UNITY_5_2_OR_NEWER\n            var prop = \"m_IncludeDependencies\";\n#else\n\t\t\tvar prop = \"m_bIncludeDependencies\";\n#endif\n\n            FieldInfo fieldInfo = packageExportT.GetField(prop, BindingFlags.NonPublic | BindingFlags.Instance);\n            if (fieldInfo == null)\n            {\n                AssetFinderLOG.LogWarning(\"Export Package error : \" + prop + \" not found !\");\n                return;\n            }\n\n            MethodInfo methodInfo =\n                packageExportT.GetMethod(\"BuildAssetList\", BindingFlags.NonPublic | BindingFlags.Instance);\n            if (methodInfo == null)\n            {\n                AssetFinderLOG.LogWarning(\"Export Package error : BuildAssetList method not found !\");\n                return;\n            }\n\n            fieldInfo.SetValue(panel, false);\n            methodInfo.Invoke(panel, null);\n            panel.Repaint();\n        }\n\n\n        public static Type GetType(string typeName)\n        {\n            var type = Type.GetType(typeName);\n            if (type != null) return type;\n\n            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())\n            {\n                type = a.GetType(typeName);\n                if (type != null) return type;\n            }\n\n            return null;\n        }\n\n        public static IEnumerable<Transform> GetAllChild(Transform root)\n        {\n            yield return root;\n            if (root.childCount <= 0) yield break;\n\n            for (var i = 0; i < root.childCount; i++)\n            {\n                foreach (Transform item in GetAllChild(root.GetChild(i)))\n                {\n                    yield return item;\n                }\n            }\n        }\n\n        public static IEnumerable<GameObject> getAllObjsInCurScene()\n        {\n#if UNITY_SCENE_MANAGER\n            for (var j = 0; j < SceneManager.sceneCount; j++)\n            {\n                Scene scene = SceneManager.GetSceneAt(j);\n                foreach (GameObject item in GetGameObjectsInScene(scene))\n                {\n                    yield return item;\n                }\n            }\n\n            if (EditorApplication.isPlaying)\n            {\n                //dont destroy scene\n                GameObject temp = null;\n                try\n                {\n                    temp = new GameObject();\n                    Object.DontDestroyOnLoad(temp);\n                    Scene dontDestroyOnLoad = temp.scene;\n                    Object.DestroyImmediate(temp);\n                    temp = null;\n\n                    foreach (GameObject item in GetGameObjectsInScene(dontDestroyOnLoad))\n                    {\n                        yield return item;\n                    }\n                } finally\n                {\n                    if (temp != null) Object.DestroyImmediate(temp);\n                }\n            }\n#else\n\t\t\tforeach (Transform obj in Resources.FindObjectsOfTypeAll(typeof(Transform)))\n            {\n\t\t\t\tGameObject o = obj.gameObject;\n               yield return o;\n            }\n#endif\n        }\n#if UNITY_SCENE_MANAGER\n        private static IEnumerable<GameObject> GetGameObjectsInScene(Scene scene)\n        {\n            var rootObjects = new List<GameObject>();\n            if (!scene.isLoaded) yield break;\n\n            scene.GetRootGameObjects(rootObjects);\n\n            // iterate root objects and do something\n            for (var i = 0; i < rootObjects.Count; ++i)\n            {\n                GameObject gameObject = rootObjects[i];\n\n                foreach (GameObject item in getAllChild(gameObject))\n                {\n                    yield return item;\n                }\n\n                yield return gameObject;\n            }\n        }\n#endif\n        public static IEnumerable<GameObject> getAllChild(GameObject target, bool returnMe = false)\n        {\n            return target.GetAllChildren(returnMe);\n        }\n\n        public static IEnumerable<Object> GetAllRefObjects(GameObject obj)\n        {\n            return obj.GetAllObjectReferences();\n        }\n\n        public static int StringMatch(string pattern, string input)\n        {\n            if (string.IsNullOrEmpty(pattern) || string.IsNullOrEmpty(input)) return 0;\n\n            pattern = pattern.ToLower();\n            input = input.ToLower();\n\n            if (input.Contains(pattern)) return 100;\n\n            int score = 0;\n            int patternIdx = 0;\n\n            for (int i = 0; i < input.Length && patternIdx < pattern.Length; i++)\n            {\n                if (input[i] == pattern[patternIdx])\n                {\n                    score += 10;\n                    patternIdx++;\n                }\n            }\n\n            return patternIdx == pattern.Length ? score : 0;\n        }\n        \n#if AssetFinderDEBUG\n\t\t[MenuItem(\"Tools/Test Prefab\")]\n\t\tstatic void TestPrefab()\n\t\t{\n\t\t\tGetPrefabParent(Selection.activeGameObject);\n\t\t}\n#endif\n\n        public static string GetPrefabParent(Object obj)\n        {\n            if (obj is GameObject go) return GetPrefabGUID(go);\n            if (obj is Component comp) return GetPrefabGUID(comp.gameObject);\n            return string.Empty;\n        }\n\n        public static string GetGameObjectPath(GameObject obj, bool includeMe = true)\n        {\n            return GetHierarchyPath(obj, includeMe);\n        }\n\n        public static bool CheckIsPrefab(GameObject obj)\n        {\n            return IsPrefabInstance(obj);\n        }\n\n        private static string GetPrefabGUID(GameObject obj)\n        {\n#if UNITY_2020_3_OR_NEWER\n            var prefabParent = PrefabUtility.GetCorrespondingObjectFromSource(obj);\n            if (prefabParent != null)\n            {\n                return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(prefabParent));\n            }\n#elif UNITY_2018_3_OR_NEWER\n            var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();\n            if (prefabStage != null && prefabStage.prefabContentsRoot == obj)\n            {\n                return AssetDatabase.AssetPathToGUID(prefabStage.prefabAssetPath);\n            }\n\n            var prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(obj);\n            if (prefabRoot != null)\n            {\n                var prefabAsset = PrefabUtility.GetCorrespondingObjectFromSource(prefabRoot);\n                if (prefabAsset != null)\n                {\n                    return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(prefabAsset));\n                }\n            }\n#else\n            var prefabParent = PrefabUtility.GetPrefabParent(obj);\n            if (prefabParent != null)\n            {\n                return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(prefabParent));\n            }\n#endif\n            return string.Empty;\n        }\n\n        private static string GetHierarchyPath(GameObject obj, bool includeMe = true)\n        {\n            if (obj == null) return string.Empty;\n\n            var path = string.Empty;\n            var current = obj.transform;\n\n            while (current != null)\n            {\n                if (current == obj.transform && !includeMe)\n                {\n                    current = current.parent;\n                    continue;\n                }\n\n                path = current.name + (string.IsNullOrEmpty(path) ? \"\" : \"/\" + path);\n                current = current.parent;\n            }\n\n            return path;\n        }\n\n        private static bool IsPrefabInstance(GameObject obj)\n        {\n#if UNITY_2018_3_OR_NEWER\n            return PrefabUtility.IsPartOfPrefabInstance(obj);\n#else\n            return PrefabUtility.GetPrefabType(obj) == PrefabType.PrefabInstance;\n#endif\n        }\n\n\n\n\n\n        public static void Clear<T1, T2>(ref Dictionary<T1, T2> dict)\n        {\n            GameObjectExtensions.InitializeOrClear(ref dict);\n        }\n\n        public static void Clear<T>(ref List<T> list)\n        {\n            GameObjectExtensions.InitializeOrClear(ref list);\n        }\n\n        public static SerializedProperty[] xGetSerializedProperties(Object go, bool processArray)\n        {\n            var so = new SerializedObject(go);\n            return so.GetAllProperties(processArray);\n        }\n\n        public static List<SerializedProperty> xGetSOArray(SerializedProperty prop)\n        {\n            int size = prop.arraySize;\n            var result = new List<SerializedProperty>();\n\n            for (var i = 0; i < size; i++)\n            {\n                SerializedProperty p = prop.GetArrayElementAtIndex(i);\n\n                if (p.isArray)\n                {\n                    result.AddRange(xGetSOArray(p.Copy()));\n                } else\n                {\n                    result.Add(p.Copy());\n                }\n            }\n\n            return result;\n        }\n\n\n\n\n        public static void BackupAndDeleteAssets(AssetFinderRef[] assets)\n        {\n            var fileName = DateTime.Now.ToString(\"yyMMdd_hhmmss\");\n\n            AssetFinderRef[] list = assets;\n            var result = new List<string>();\n\n\n            var selectedList = new List<string>();\n\n            foreach (AssetFinderRef item in list)\n            {\n                if (item.asset == null) continue;\n                string oPath = item.asset.assetPath.Replace(\"\\\\\", \"/\");\n                if (!oPath.StartsWith(\"Assets/\")) continue;\n                result.Add(item.asset.assetPath);\n\n                if (item.isSelected()) selectedList.Add(item.asset.assetPath);\n            }\n            if (selectedList.Count != 0) result = selectedList;\n            Directory.CreateDirectory(\"Library/FR2/\");\n            AssetDatabase.ExportPackage(result.ToArray(), \"Library/FR2/bk_\" + fileName + \".unitypackage\");\n\n            AssetDatabase.StartAssetEditing();\n            try\n            {\n                for (var i = 0; i < result.Count; i++)\n                {\n                    AssetDatabase.DeleteAsset(result[i]);\n                }\n            } finally\n            {\n                AssetDatabase.StopAssetEditing();\n                AssetDatabase.Refresh();\n            }\n\n            AssetFinderCache.DelayCheck4Changes();\n        }\n\n\n\n\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/AssetFinderUnity.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 65be7edb17b7a8b4092a809fc881f206\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/GUI2.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Profiling;\nusing Object = UnityEngine.Object;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public interface IDrawer\n    {\n        bool Draw(Rect rect);\n        bool DrawLayout();\n    }\n\n    internal static class AssetFinderGUI\n    {\n\n        public static GUIColor Color(Color c)\n        {\n            return new GUIColor(c);\n        }\n        public static GUIContentColor ContentColor(Color c)\n        {\n            return new GUIContentColor(c);\n        }\n        public static GUIBackgroundColor BackgroundColor(Color c)\n        {\n            return new GUIBackgroundColor(c);\n        }\n        internal class GUIColor : IDisposable\n        {\n            private readonly Color color;\n            public GUIColor(Color c)\n            {\n                color = GUI.color;\n                GUI.color = c;\n            }\n            public void Dispose()\n            {\n                GUI.color = color;\n            }\n        }\n\n        internal class GUIContentColor : IDisposable\n        {\n            private readonly Color color;\n            public GUIContentColor(Color c)\n            {\n                color = GUI.contentColor;\n                GUI.contentColor = c;\n            }\n            public void Dispose()\n            {\n                GUI.contentColor = color;\n            }\n        }\n\n        internal class GUIBackgroundColor : IDisposable\n        {\n            private readonly Color color;\n            public GUIBackgroundColor(Color c)\n            {\n                color = GUI.backgroundColor;\n                GUI.backgroundColor = c;\n            }\n            public void Dispose()\n            {\n                GUI.backgroundColor = color;\n            }\n        }\n    }\n\n\n\n\n\n\n\n    internal static class GUI2\n    {\n\n        internal static Dictionary<string, GUIContent> tooltipCache = new Dictionary<string, GUIContent>();\n\n        // -----------------------\n\n        private static GUIStyle _miniLabelAlignRight;\n\n        public static Color darkRed = new Color(0.5f, .0f, 0f, 1f);\n        public static Color darkGreen = new Color(0, .5f, 0f, 1f);\n        public static Color darkBlue = new Color(0, .0f, 0.5f, 1f);\n        public static Color lightRed = new Color(1f, 0.5f, 0.5f, 1f);\n\n\n        public static readonly GUILayoutOption[] GLW_20 = { GUILayout.Width(20f) };\n        public static readonly GUILayoutOption[] GLW_24 = { GUILayout.Width(24f) };\n        public static readonly GUILayoutOption[] GLW_50 = { GUILayout.Width(50f) }; // Legacy compact size\n        public static readonly GUILayoutOption[] GLW_70 = { GUILayout.Width(70f) }; // Legacy medium size  \n        public static readonly GUILayoutOption[] GLW_80 = { GUILayout.Width(80f) }; // Legacy standard size\n        public static readonly GUILayoutOption[] GLW_100 = { GUILayout.Width(100f) };\n        public static readonly GUILayoutOption[] GLW_120 = { GUILayout.Width(120f) }; // Legacy wide size\n        public static readonly GUILayoutOption[] GLW_140 = { GUILayout.Width(140f) }; // Legacy extra wide size\n        public static readonly GUILayoutOption[] GLW_150 = { GUILayout.Width(150f) };\n        public static readonly GUILayoutOption[] GLW_160 = { GUILayout.Width(160f) };\n        public static readonly GUILayoutOption[] GLW_320 = { GUILayout.Width(320f) };\n\n\n        public static GUIStyle miniLabelAlignRight\n        {\n            get\n            {\n                if (_miniLabelAlignRight != null) return _miniLabelAlignRight;\n                return _miniLabelAlignRight = new GUIStyle(EditorStyles.miniLabel) { alignment = TextAnchor.MiddleRight };\n            }\n        }\n\n        public static void Color(Action a, Color c, float? alpha = null)\n        {\n            if (a == null) return;\n\n            Color cColor = GUI.color;\n            if (alpha != null) c.a = alpha.Value;\n\n            GUI.color = c;\n            a();\n            GUI.color = cColor;\n        }\n\n        public static void ContentColor(Action a, Color c, float? alpha = null)\n        {\n            if (a == null) return;\n\n            Color cColor = GUI.contentColor;\n            if (alpha != null) c.a = alpha.Value;\n\n            GUI.contentColor = c;\n            a();\n            GUI.contentColor = cColor;\n        }\n\n        public static void BackgroundColor(Action a, Color c, float? alpha = null)\n        {\n            if (a == null) return;\n\n            Color cColor = GUI.backgroundColor;\n            if (alpha != null) c.a = alpha.Value;\n\n            GUI.backgroundColor = c;\n            a();\n            GUI.backgroundColor = cColor;\n        }\n\n        public static Color Theme(Color proColor, Color indieColor)\n        {\n            return EditorGUIUtility.isProSkin ? proColor : indieColor;\n        }\n\n        public static Color Alpha(Color c, float a)\n        {\n            c.a = a;\n            return c;\n        }\n\n        public static void Rect(Rect r, Color c, float? alpha = null)\n        {\n            Color cColor = GUI.color;\n            if (alpha != null) c.a = alpha.Value;\n\n            GUI.color = c;\n            GUI.DrawTexture(r, Texture2D.whiteTexture);\n            GUI.color = cColor;\n        }\n\n        public static Object[] DropZone(string title, float w, float h)\n        {\n            Rect rect = GUILayoutUtility.GetRect(w, h);\n            GUI.Box(rect, GUIContent.none, EditorStyles.textArea);\n\n            float cx = rect.x + w / 2f;\n            float cy = rect.y + h / 2f;\n            float pz = w / 3f; // plus size\n\n            var plusRect = new Rect(cx - pz / 2f, cy - pz / 2f, pz, pz);\n            Color(() => { GUI.DrawTexture(plusRect, AssetFinderIcon.Plus.image, ScaleMode.ScaleToFit); }, UnityEngine.Color.white, 0.1f);\n\n            GUI.Label(rect, title, EditorStyles.wordWrappedMiniLabel);\n\n            EventType eventType = Event.current.type;\n            var isAccepted = false;\n\n            if (eventType == EventType.DragUpdated || eventType == EventType.DragPerform)\n            {\n                DragAndDrop.visualMode = DragAndDropVisualMode.Copy;\n\n                if (eventType == EventType.DragPerform)\n                {\n                    DragAndDrop.AcceptDrag();\n                    isAccepted = true;\n                }\n                Event.current.Use();\n            }\n\n            return isAccepted ? DragAndDrop.objectReferences : null;\n        }\n\n        //        public static bool ColorIconButton(Rect r, Texture icon, Vector2? iconOffset, Color? c)\n        //        {\n        //            if (c != null) Rect(r, c.Value);\n        //            \n        //            // align center\n        //            if (iconOffset != null)\n        //            {\n        //                r.x += iconOffset.Value.x;\n        //                r.y += iconOffset.Value.y;\n        //            }\n        //            \n        //            return GUI.Button(r, icon, GUIStyle.none);\n        //        }\n\n        public static bool ColorIconButton(Rect r, Texture icon, Color? c)\n        {\n            Color oColor = GUI.color;\n            if (c != null) GUI.color = c.Value;\n            bool result = GUI.Button(r, icon, GUIStyle.none);\n            GUI.color = oColor;\n            return result;\n        }\n\n        public static bool Toggle(Rect r, ref bool value, string label, GUIStyle style, params GUILayoutOption[] options)\n        {\n            GUIContent guiContent = AssetFinderGUIContent.From(label);\n            bool vv = GUI.Toggle(r, value, guiContent, style);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        public static bool Toggle(ref bool value, string label, GUIStyle style, params GUILayoutOption[] options)\n        {\n            GUIContent guiContent = AssetFinderGUIContent.From(label);\n            bool vv = GUILayout.Toggle(value, guiContent, style, options);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        public static bool Toggle(ref bool value, Texture2D tex, GUIStyle style, params GUILayoutOption[] options)\n        {\n            bool vv = GUILayout.Toggle(value, tex, style, options);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        public static bool Toggle(Rect r, ref bool value, GUIContent tex, GUIStyle style)\n        {\n            bool vv = GUI.Toggle(r, value, tex, style);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n        public static bool Toggle(ref bool value, GUIContent tex, GUIStyle style, params GUILayoutOption[] options)\n        {\n            bool vv = GUILayout.Toggle(value, tex, style, options);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        public static bool Toggle(Rect rect, ref bool value, GUIContent tex)\n        {\n            bool vv = GUI.Toggle(rect, value, tex, GUIStyle.none);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        public static bool Toggle(Rect rect, ref bool value)\n        {\n            bool vv = GUI.Toggle(rect, value, GUIContent.none);\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        internal static bool Toggle(bool v, string label, Action<bool> setter)\n        {\n            GUIContent guiContent = AssetFinderGUIContent.From(label);\n            bool v1 = GUILayout.Toggle(v, guiContent);\n            if (v1 == v) return false;\n            if (setter != null) setter(v1);\n            return true;\n        }\n\n        internal static bool ToolbarToggle(Rect r, ref bool value, Texture icon, Vector2 padding, string tooltip = null)\n        {\n            //TODO: FIX GC\n            bool vv = GUI.Toggle(r, value, AssetFinderGUIContent.Tooltip(tooltip), EditorStyles.toolbarButton);\n\n            if (icon != null)\n            {\n                Rect rect = GUILayoutUtility.GetLastRect();\n                rect = Padding(rect, padding.x, padding.y);\n                GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit);\n            }\n\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n\n        internal static bool GUI_ToggleOptimize(Rect r, bool value, GUIContent content)\n        {\n            EventType eventType = Event.current.type;\n\n            if (eventType == EventType.MouseDown)\n            {\n                return GUI.Toggle(r, value, content, EditorStyles.toolbarButton);\n            }\n\n            if (eventType == EventType.Repaint)\n            {\n                GUI.DrawTexture(r, content.image, ScaleMode.ScaleToFit);\n            }\n            return false;\n        }\n\n        public static bool ToolbarToggle(ref bool value, Texture icon, Vector2 padding, string tooltip, Rect position)\n        {\n            // Draw the toggle button directly at the specified position\n            bool newValue = GUI.Toggle(position, value, AssetFinderGUIContent.FromTexture(icon, tooltip), EditorStyles.toolbarButton);\n\n            // Update the reference value\n            bool changed = newValue != value;\n            value = newValue;\n\n            return changed;\n        }\n\n        // Example implementation of a Toggle\n        public static bool Toggle(ref bool value, GUIContent content, GUIStyle style, Rect position)\n        {\n            // Draw the toggle button directly at the specified position\n            bool newValue = GUI.Toggle(position, value, content, style);\n\n            // Update the reference value\n            bool changed = newValue != value;\n            value = newValue;\n\n            return changed;\n        }\n\n        internal static bool ToolbarToggle(Rect r, ref bool value, GUIContent content)\n        {\n            if (value == false)\n            {\n                if (GUI.Toggle(r, value, content, EditorStyles.toolbarButton) != value)\n                {\n                    value = true;\n                    return true;\n                }\n\n                return false;\n            }\n\n\n            if (GUI.Toggle(r, value, content, EditorStyles.toolbarButton) == false)\n            {\n                value = false;\n                return true;\n            }\n\n            return false;\n        }\n\n        internal static bool ToolbarToggle(ref bool value, Texture icon, Vector2 padding, string tooltip = null)\n        {\n            var vv = false;\n            Profiler.BeginSample(\"FR2-GUI2.ToolbarToggle\");\n            {\n                vv = GUILayout.Toggle(value, AssetFinderGUIContent.Tooltip(tooltip), EditorStyles.toolbarButton, GLW_24);\n                if (icon != null)\n                {\n                    Rect rect = GUILayoutUtility.GetLastRect();\n                    rect = Padding(rect, padding.x, padding.y);\n                    GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit);\n                }\n            }\n            Profiler.EndSample();\n\n            if (vv == value) return false;\n            value = vv;\n            return true;\n        }\n        \n        internal static bool ToolbarToggle(ref bool value, Texture icon, Vector2 padding, string tooltip, Rect position, bool hasContent = false)\n        {\n            // Apply special coloring when button is OFF but has content to show\n            Color originalColor = GUI.backgroundColor;\n            if (!value && hasContent)\n            {\n                GUI.backgroundColor = UnityEngine.Color.yellow; // Yellow background when off but has content\n            }\n            \n            // Draw the toggle button directly at the specified position\n            bool newValue = GUI.Toggle(position, value, AssetFinderGUIContent.FromTexture(icon, tooltip), EditorStyles.toolbarButton);\n\n            // Update the reference value\n            bool changed = newValue != value;\n            value = newValue;\n            \n            // Restore original color\n            GUI.backgroundColor = originalColor;\n\n            return changed;\n        }\n\n        // internal static bool GUILayoutToggle(ref bool value, string tooltip)\n        // {\n        //     Profiler.BeginSample(\"FR2-GUI2.ToolbarToggle2-step1\");\n        //     Rect rect = GUILayoutUtility.GetRect(24, 24, 18f, 18f);\n        //     Profiler.EndSample();\n        //     \n        //     Profiler.BeginSample(\"FR2-GUI2.ToolbarToggle2-step2\");\n        //     bool oldValue = value;\n        //     value = GUI.Toggle(rect, value, AssetFinderGUIContent.Tooltip(tooltip), EditorStyles.toolbarButton);\n        //     Profiler.EndSample();\n        //     \n        //     return oldValue != value;\n        // }\n\n        // TODO : optimize for performance\n        // public static bool EnumPopup<T>(ref T mode, string label, float labelWidth, GUIStyle style, params GUILayoutOption[] options)\n        // {\n        //     var sz = EditorGUIUtility.labelWidth;\n        //     EditorGUIUtility.labelWidth = labelWidth;\n        //     {\n        //         var obj = (Enum)(object)mode;\n        //         var vv = EditorGUILayout.EnumPopup(label, obj, style, options);\n        //         if (Equals(vv, obj))\n        //         {\n        //             EditorGUIUtility.labelWidth = sz;\n        //             return false;\n        //         }\n\n        //         mode = (T)(object)vv;\n        //     }\n        //     EditorGUIUtility.labelWidth = sz;\n        //     return true;\n        // }\n\n        // public static bool EnumPopup<T>(ref T mode, GUIContent icon, GUIStyle style, params GUILayoutOption[] options)\n        // {\n        //     var obj = (Enum)(object)mode;\n        //     var cRect = GUILayoutUtility.GetRect(16f, 16f);\n\n        // \tif (Event.current.type == EventType.Repaint)\n        // \t{\n        // \t\tcRect.xMin -= 2f;\n        // \t\tcRect.yMin += 2f;\n        // \t\tGUI.Label(cRect, icon);\n        // \t}\n\n        // \tif (Event.current.type == EventType.MouseDown && Event.current.button == 0)\n        // \t{\n        // \t\tvar vv = EditorGUILayout.EnumPopup(obj, style, options);\n        // \t\tif (Equals(vv, obj))\n        // \t\t{\n        // \t\t\treturn false;\n        // \t\t}\n        // \t\tmode = (T)(object)vv;\n        // \t\treturn true;\n        // \t}\n\n        // \t//if (Event.current.type == EventType.Repaint)\n        // \t{\n        // \t\tEditorGUILayout.LabelField(AssetFinderGUIContent.FromString(\"Hello\"), style, options);\n        // \t}\n\n        // \treturn false;\n        // }\n\n        public static Rect Padding(Rect r, float x, float y)\n        {\n            return new Rect(r.x + x, r.y + y, r.width - 2 * x, r.height - 2 * y);\n        }\n\n        public static Rect LeftRect(float w, ref Rect rect)\n        {\n            rect.x += w;\n            rect.width -= w;\n            return new Rect(rect.x - w, rect.y, w, rect.height);\n        }\n\n        public static Rect RightRect(float w, ref Rect rect)\n        {\n            rect.width -= w;\n            return new Rect(rect.x + rect.width, rect.y, w, rect.height);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension/GUI2.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9fa484b2aa858464fb8254e4bbf1f6ac\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extension.meta",
    "content": "fileFormatVersion: 2\nguid: 7c7413730e214b0ab9b5a7a25cbd9a44\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/AssetFinderWindowExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class AssetFinderWindowExtensions\n    {\n        // Panel visibility extensions\n        internal static bool IsScenePanelVisible(this AssetFinderWindowAll window)\n        {\n            if (window.isFocusingAddressable) return false;\n\n            if (window.selection.isSelectingAsset && window.isFocusingUses) // Override\n            {\n                return false;\n            }\n\n            if (!window.selection.isSelectingAsset && window.isFocusingUsedBy)\n            {\n                return true;\n            }\n\n            return window.settings.scene;\n        }\n\n        internal static bool IsAssetPanelVisible(this AssetFinderWindowAll window)\n        {\n            if (window.isFocusingAddressable) return false;\n\n            if (window.selection.isSelectingAsset && window.isFocusingUses) // Override\n            {\n                return true;\n            }\n\n            if (!window.selection.isSelectingAsset && window.isFocusingUsedBy)\n            {\n                return false;\n            }\n\n            return window.settings.asset;\n        }\n\n        internal static void RefreshPanelVisibility(this AssetFinderWindowAll window)\n        {\n            window.sp2.splits[0].visible = window.IsScenePanelVisible();\n            window.sp2.splits[1].visible = window.IsAssetPanelVisible();\n            window.sp2.splits[2].visible = window.isFocusingAddressable;\n            window.sp2.CalculateWeight();\n        }\n\n        // Selection management extensions\n        internal static UnityObject[] GetCachedSelectionExtension(this AssetFinderWindowAll window)\n        {\n            int currentFrame = Time.frameCount;\n            if (window._cachedSelectionFrame != currentFrame)\n            {\n                window._cachedSelection = Selection.objects;\n                window._cachedSelectionFrame = currentFrame;\n            }\n            return window._cachedSelection;\n        }\n\n        // Asset drawer extension\n        internal static AssetFinderRefDrawer GetAssetDrawerExtension(this AssetFinderWindowAll window)\n        {\n            if (window.isFocusingUses) return window.selection.isSelectingAsset ? window.UsesDrawer : window.SceneToAssetDrawer;\n            if (window.isFocusingUsedBy) return window.selection.isSelectingAsset ? window.UsedByDrawer : null;\n            if (window.isFocusingAddressable) return window.AddressableDrawer.drawer;\n            return null;\n        }\n        \n        internal static void OnCSVClickExtension(this AssetFinderWindowAll window)\n        {\n            AssetFinderRef[] csvSource = null;\n            AssetFinderRefDrawer drawer = window.GetAssetDrawerExtension();\n\n            if (drawer != null) csvSource = drawer.source;\n\n            if (window.isFocusingUnused && (csvSource == null)) csvSource = window.RefUnUse.source;\n            if (window.isFocusingUsedInBuild && (csvSource == null)) csvSource = AssetFinderRef.FromDict(window.UsedInBuild.refs);\n            if (window.isFocusingDuplicate && (csvSource == null)) csvSource = AssetFinderRef.FromList(window.Duplicated.list);\n\n            AssetFinderExport.ExportCSV(csvSource);\n        }\n        \n        internal static void CacheAllDrawers(this AssetFinderWindowAll window)\n        {\n            window._allDrawersCache = new AssetFinderRefDrawer[]\n            {\n                window.UsedByDrawer,\n                window.UsesDrawer,\n                window.SceneToAssetDrawer,\n                window.RefUnUse,\n                window.RefInScene,\n                window.RefSceneInScene,\n                window.SceneUsesDrawer,\n                window.UsedInBuild.Drawer\n            };\n        }\n\n        internal static void RefreshShowUsageType(this AssetFinderWindowAll window)\n        {\n            if (window._allDrawersCache != null)\n            {\n                foreach (var drawer in window._allDrawersCache)\n                {\n                    if (drawer != null && drawer.AssetConfig != null) drawer.AssetConfig.showUsageType = window.settings.showUsageType;\n                }\n            }\n        }\n\n        internal static void RefreshSort(this AssetFinderWindowAll window)\n        {\n            if (window._allDrawersCache != null)\n            {\n                foreach (var drawer in window._allDrawersCache)\n                {\n                    drawer?.RefreshSort();\n                }\n            }\n            window.AddressableDrawer.RefreshSort();\n            window.Duplicated.RefreshSort();\n            window.UsedInBuild.RefreshSort();\n            \n            // Ensure tool-specific drawers are also refreshed\n            if (window.settings.toolMode)\n            {\n                window.RefUnUse?.RefreshSort();\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/AssetFinderWindowExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 393ff0810b1b94cefabaa2d9449560ee\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/CollectionExtensions.cs",
    "content": "using System.Collections.Generic;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class CollectionExtensions\n    {\n        internal static HashSet<T> ToHashSet<T>(this IEnumerable<T> collection)\n        {\n            var result = new HashSet<T>();\n            if (collection == null) return result;\n\n            foreach (T item in collection)\n            {\n                result.Add(item);\n            }\n            return result;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/CollectionExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1dbc4e32a727c4ecdb4be457da481199\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/ColorExtensions.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class ColorExtensions\n    {\n        internal static Color Alpha(this Color c, float alpha)\n        {\n            return new Color(c.r, c.g, c.b, alpha);\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/ColorExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d9b900ca884e345308acc476c8af4e53\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/DictionaryExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class DictionaryExtensions\n    {\n        #if UNITY_2021_2_OR_NEWER\n        // GetValueOrDefault exists in newer Unity versions\n        #else\n        internal static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue = default(TValue))\n        {\n            return dictionary.TryGetValue(key, out TValue value) ? value : defaultValue;\n        }\n        #endif\n        \n        internal static TValue TryGetValueOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)\n        {\n            if (dictionary.TryGetValue(key, out TValue value))\n                return value;\n            \n            dictionary[key] = defaultValue;\n            return defaultValue;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/DictionaryExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3f57a4bab3eb042b981518071fa681fa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/GameObjectExtensions.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.SceneManagement;\nusing UnityEditor;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class GameObjectExtensions\n    {\n        internal static IEnumerable<GameObject> GetAllChildren(this GameObject target, bool includeTarget = false)\n        {\n            if (target == null) yield break;\n            \n            if (includeTarget) yield return target;\n\n            if (target.transform.childCount > 0)\n            {\n                for (var i = 0; i < target.transform.childCount; i++)\n                {\n                    var child = target.transform.GetChild(i).gameObject;\n                    if (child == null) continue;\n                    \n                    yield return child;\n                    \n                    foreach (var grandChild in child.GetAllChildren(false))\n                    {\n                        yield return grandChild;\n                    }\n                }\n            }\n        }\n        \n        internal static IEnumerable<Transform> GetAllChildTransforms(this Transform root)\n        {\n            yield return root;\n            \n            for (var i = 0; i < root.childCount; i++)\n            {\n                var child = root.GetChild(i);\n                foreach (var descendant in child.GetAllChildTransforms())\n                {\n                    yield return descendant;\n                }\n            }\n        }\n        \n        internal static IEnumerable<GameObject> GetAllGameObjectsInCurrentScenes()\n        {\n            for (var j = 0; j < SceneManager.sceneCount; j++)\n            {\n                var scene = SceneManager.GetSceneAt(j);\n                foreach (var gameObject in scene.GetAllGameObjects())\n                {\n                    yield return gameObject;\n                }\n            }\n\n            if (EditorApplication.isPlaying)\n            {\n                GameObject temp = null;\n                try\n                {\n                    temp = new GameObject();\n                    UnityObject.DontDestroyOnLoad(temp);\n                    var dontDestroyOnLoad = temp.scene;\n                    UnityObject.DestroyImmediate(temp);\n                    temp = null;\n\n                    foreach (var gameObject in dontDestroyOnLoad.GetAllGameObjects())\n                    {\n                        yield return gameObject;\n                    }\n                }\n                finally\n                {\n                    if (temp != null) UnityObject.DestroyImmediate(temp);\n                }\n            }\n        }\n        \n        internal static IEnumerable<GameObject> GetAllGameObjects(this Scene scene)\n        {\n            if (!scene.isLoaded) yield break;\n            \n            var rootObjects = new List<GameObject>();\n            scene.GetRootGameObjects(rootObjects);\n\n            for (var i = 0; i < rootObjects.Count; ++i)\n            {\n                var rootObject = rootObjects[i];\n                \n                foreach (var child in rootObject.GetAllChildren(false))\n                {\n                    yield return child;\n                }\n                \n                yield return rootObject;\n            }\n        }\n        \n        internal static void InitializeOrClear<T>(ref List<T> list)\n        {\n            if (list == null)\n            {\n                list = new List<T>();\n            }\n            else\n            {\n                list.Clear();\n            }\n        }\n        \n        internal static void InitializeOrClear<TKey, TValue>(ref Dictionary<TKey, TValue> dictionary)\n        {\n            if (dictionary == null)\n            {\n                dictionary = new Dictionary<TKey, TValue>();\n            }\n            else\n            {\n                dictionary.Clear();\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/GameObjectExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 20b7c860188d14e36883165f4230bab3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/RectExtensions.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class RectExtensions\n    {\n        internal static (Rect, Rect) HzSplit(this Rect r, float space = 8f, float ratio = 0.5f)\n        {\n            var w = (r.width - space) * ratio;\n            var r1 = new Rect(r.x, r.y, w, r.height);\n            var r2 = new Rect(r.x + w + space, r.y, r.width - w - space, r.height);\n            return (r1, r2);\n        }\n\n        internal static (Rect left, Rect flex) ExtractLeft(this Rect r, float leftWidth = 16f, float space = 0f)\n        {\n            var left = new Rect(r.x, r.y, leftWidth, r.height);\n            var flex = new Rect(r.x + leftWidth + space, r.y, r.width - leftWidth - space, r.height);\n            return (left, flex);\n        }\n\n        internal static (Rect right, Rect flex) ExtractRight(this Rect r, float rightWidth = 16f, float space = 0f)\n        {\n            var right = new Rect(r.x + r.width - rightWidth, r.y, rightWidth, r.height);\n            var flex = new Rect(r.x, r.y, r.width - rightWidth - space, r.height);\n            return (right, flex);\n        }\n\n        internal static Rect LPad(this Rect r, float padding = 8f, bool padCondition = true)\n        {\n            return padCondition ? new Rect(r.x + padding, r.y, r.width - padding, r.height) : r;\n        }\n\n        internal static Rect RPad(this Rect r, float padding = 8f, bool padCondition = true)\n        {\n            return padCondition ? new Rect(r.x, r.y, r.width - padding, r.height) : r;\n        }\n\n        internal static Rect Pad(this Rect r, float padLeft = 8f, float padRight = 8f, bool padCondition = true)\n        {\n            return padCondition ? new Rect(r.x + padLeft, r.y, r.width - padLeft - padRight, r.height) : r;\n        }\n\n        internal static Rect Move(this Rect r, float dx = 0f, float dy = 0f)\n        {\n            return new Rect(r.x + dx, r.y + dy, r.width, r.height);\n        }\n\n        internal static Rect SetHeight(this Rect r, float h)\n        {\n            return new Rect(r.x, r.y, r.width, h);\n        }\n\n        internal static Rect SetWidth(this Rect r, float w)\n        {\n            return new Rect(r.x, r.y, w, r.height);\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/RectExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d3ef94fba7a6949beb1eeb13be0b2e6a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/RectGUIExtensions.cs",
    "content": "using System;\nusing UnityEngine;\nusing UnityEditor;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class RectGUIExtensions\n    {\n        internal static Rect OnRightClick(this Rect rect, Action onRightClick, float padding = 0f)\n        {\n            var padRect = rect.Pad(padding, padding);\n            if (Event.current.type == EventType.MouseDown && Event.current.button == 1)\n            {\n                if (padRect.Contains(Event.current.mousePosition))\n                {\n                    onRightClick?.Invoke();\n                    Event.current.Use();\n                }\n            }\n\n            return rect;\n        }\n\n        internal static Rect OnLeftClick(this Rect rect, Action onClick, float padding = 0f)\n        {\n            var padRect = rect.Pad(padding, padding);\n            if (Event.current.type == EventType.MouseDown && Event.current.button == 0)\n            {\n                if (padRect.Contains(Event.current.mousePosition))\n                {\n                    onClick?.Invoke();\n                    Event.current.Use();\n                }\n            }\n\n            return rect;\n        }\n\n        internal static Rect OnDoubleClick(this Rect rect, Action onDoubleClick, float padding = 0f)\n        {\n            var padRect = rect.Pad(padding, padding);\n            if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.clickCount == 2)\n            {\n                if (padRect.Contains(Event.current.mousePosition))\n                {\n                    onDoubleClick?.Invoke();\n                    Event.current.Use();\n                }\n            }\n\n            return rect;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/RectGUIExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c7cd0bdf6c8394e4cbde439e5052c9bb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/SerializedObjectExtensions.cs",
    "content": "using System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class SerializedObjectExtensions\n    {\n        internal static IEnumerable<UnityObject> GetAllObjectReferences(this SerializedObject serializedObject)\n        {\n            SerializedProperty iterator = serializedObject.GetIterator().Copy();\n            while (iterator.NextVisible(true))\n            {\n                if (iterator.propertyType != SerializedPropertyType.ObjectReference) continue;\n                if (iterator.objectReferenceValue == null) continue;\n                \n                yield return iterator.objectReferenceValue;\n            }\n        }\n        \n        internal static IEnumerable<UnityObject> GetAllObjectReferences(this Component component)\n        {\n            if (component == null) yield break;\n            \n            var serializedObject = new SerializedObject(component);\n            foreach (var obj in serializedObject.GetAllObjectReferences())\n            {\n                yield return obj;\n            }\n        }\n        \n        internal static IEnumerable<UnityObject> GetAllObjectReferences(this GameObject gameObject)\n        {\n            if (gameObject == null) yield break;\n            \n            var components = gameObject.GetComponents<Component>();\n            foreach (var component in components)\n            {\n                foreach (var obj in component.GetAllObjectReferences())\n                {\n                    yield return obj;\n                }\n            }\n        }\n        \n        internal static SerializedProperty[] GetAllProperties(this SerializedObject serializedObject, bool processArrays = false)\n        {\n            serializedObject.Update();\n            var result = new List<SerializedProperty>();\n            \n            SerializedProperty iterator = serializedObject.GetIterator();\n            while (iterator.NextVisible(true))\n            {\n                SerializedProperty copy = iterator.Copy();\n                \n                if (processArrays && iterator.isArray)\n                {\n                    result.AddRange(GetArrayProperties(copy));\n                }\n                else\n                {\n                    result.Add(copy);\n                }\n            }\n            \n            return result.ToArray();\n        }\n        \n        private static List<SerializedProperty> GetArrayProperties(SerializedProperty arrayProperty)\n        {\n            var result = new List<SerializedProperty>();\n            int size = arrayProperty.arraySize;\n            \n            for (int i = 0; i < size; i++)\n            {\n                SerializedProperty element = arrayProperty.GetArrayElementAtIndex(i);\n                \n                if (element.isArray)\n                {\n                    result.AddRange(GetArrayProperties(element.Copy()));\n                }\n                else\n                {\n                    result.Add(element.Copy());\n                }\n            }\n            \n            return result;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/SerializedObjectExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ce68eca29b021402ea48c05018c4ca1e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/TabExtensions.cs",
    "content": "using System;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class TabExtensions\n    {\n        internal static bool IsFocusing(this AssetFinderTabView tabView, int index)\n        {\n            return tabView != null && tabView.current == index;\n        }\n\n        internal static bool IsFocusingAny(this AssetFinderTabView tabView, params int[] indices)\n        {\n            if (tabView == null) return false;\n            foreach (int index in indices)\n            {\n                if (tabView.current == index) return true;\n            }\n            return false;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/TabExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 760bc254844c546a2a7f851252c1ca3b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/UnityObjectExtensions.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System.Linq;\nusing System.Collections.Generic;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class UnityObjectExtensions\n    {\n        public static bool IsSceneObject(this UnityObject obj)\n        {\n            // null, destroyed or asset-stored objects all return false\n            return obj != null && !EditorUtility.IsPersistent(obj) && (obj is GameObject || obj is Component);\n        }\n\n        public static bool IsAssetObject(this UnityObject obj)\n        {\n            return obj != null && EditorUtility.IsPersistent(obj);\n        }\n\n        internal static GameObject GetGameObjectFromTarget(this UnityObject target)\n        {\n            if (!target) return null;\n            if (target is GameObject go) return go;\n            if (target is Component comp && comp != null) return comp.gameObject;\n            return null;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions/UnityObjectExtensions.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f00e2486baaa5468d977d31d88435a06\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Extensions.meta",
    "content": "fileFormatVersion: 2\nguid: c31023e7608e64d93882b110fcd25d84\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ASMStatus.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    public static partial class AssetFinderAddressable\n    {\n        public enum ASMStatus\n        {\n            None,\n            AsmNotFound,\n            TypeNotFound,\n            FieldNotFound,\n            AsmOK\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ASMStatus.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5165551de58ead041ad896718828125d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.AddressInfo.cs",
    "content": "using System;\nusing System.Collections.Generic;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public static partial class AssetFinderAddressable\n    {\n        [Serializable]\n        public class AddressInfo\n        {\n            public string address;\n            public string bundleGroup;\n            public HashSet<string> assetGUIDs;\n            public HashSet<string> childGUIDs;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.AddressInfo.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e6b0b5f786f9112409dbf87d86874dd8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ProjectStatus.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    public static partial class AssetFinderAddressable\n    {\n        public enum ProjectStatus\n        {\n            None,\n            NoSettings,\n            NoGroup,\n            Ok\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.ProjectStatus.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7b7933c9a7e39144db38a73ad4ffb618\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing UnityEditor;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public static partial class AssetFinderAddressable\n    {\n\n        private static Assembly asm;\n        private static Type addressableAssetGroupType;\n        private static Type addressableAssetEntryType;\n\n        private static PropertyInfo entriesProperty;\n        private static PropertyInfo groupNameProperty;\n        private static PropertyInfo addressProperty;\n        private static PropertyInfo guidProperty;\n        private static PropertyInfo settingsProperty;\n        private static PropertyInfo groupsProperty;\n\n        static AssetFinderAddressable()\n        {\n            Scan();\n        }\n\n        public static bool isOk => (asmStatus == ASMStatus.AsmOK) && (projectStatus == ProjectStatus.Ok);\n\n        public static ASMStatus asmStatus { get; private set; }\n        public static ProjectStatus projectStatus { get; private set; }\n\n        public static void Scan()\n        {\n            asm = GetAssembly();\n            if (asm == null)\n            {\n                asmStatus = ASMStatus.AsmNotFound;\n                return;\n            }\n\n            Type addressableSettingsType = GetAddressableType(\"UnityEditor.AddressableAssets.Settings.AddressableAssetSettings\");\n            Type addressableSettingsDefaultObjectType = GetAddressableType(\"UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject\");\n            addressableAssetGroupType = GetAddressableType(\"UnityEditor.AddressableAssets.Settings.AddressableAssetGroup\");\n            addressableAssetEntryType = GetAddressableType(\"UnityEditor.AddressableAssets.Settings.AddressableAssetEntry\");\n\n            if (addressableSettingsType == null || addressableSettingsDefaultObjectType == null || addressableAssetGroupType == null || addressableAssetEntryType == null)\n            {\n                asmStatus = ASMStatus.TypeNotFound;\n                return;\n            }\n\n            entriesProperty = addressableAssetGroupType.GetProperty(\"entries\", BindingFlags.Public | BindingFlags.Instance);\n            groupNameProperty = addressableAssetGroupType.GetProperty(\"Name\", BindingFlags.Public | BindingFlags.Instance);\n            addressProperty = addressableAssetEntryType.GetProperty(\"address\", BindingFlags.Public | BindingFlags.Instance);\n            guidProperty = addressableAssetEntryType.GetProperty(\"guid\", BindingFlags.Public | BindingFlags.Instance);\n            settingsProperty = addressableSettingsDefaultObjectType.GetProperty(\"Settings\", BindingFlags.Public | BindingFlags.Static);\n            groupsProperty = addressableSettingsType.GetProperty(\"groups\", BindingFlags.Public | BindingFlags.Instance);\n\n            if (entriesProperty == null || groupNameProperty == null || addressProperty == null || guidProperty == null)\n            {\n                asmStatus = ASMStatus.FieldNotFound;\n                return;\n            }\n\n            asmStatus = ASMStatus.AsmOK;\n            projectStatus = ProjectStatus.None;\n        }\n\n        private static Assembly GetAssembly()\n        {\n            const string DLL = \"Unity.Addressables.Editor\";\n            Assembly[] allAssemblies = AppDomain.CurrentDomain.GetAssemblies();\n            foreach (Assembly item in allAssemblies)\n            {\n                if (item.GetName().Name != DLL) continue;\n                \n                return item;\n            }\n            \n            return null;\n        }\n\n        private static Type GetAddressableType(string typeName)\n        {\n            return asm == null ? null : asm.GetType(typeName);\n        }\n\n        /// <summary>\n        ///     Get a map between address -> AddressInfo (assetGUIDs + childGUIDs)\n        /// </summary>\n        /// <returns></returns>\n        public static Dictionary<string, AddressInfo> GetAddresses()\n        {\n            if (asmStatus != ASMStatus.AsmOK) return null;\n\n            // Get the AddressableAssetSettings instance\n            object settings = settingsProperty?.GetValue(null);\n\n            if (settings == null)\n            {\n                projectStatus = ProjectStatus.NoSettings;\n                return null;\n            }\n\n            var addresses = new Dictionary<string, AddressInfo>();\n            var groups = groupsProperty?.GetValue(settings) as IEnumerable<object>;\n\n            if (groups == null)\n            {\n                projectStatus = ProjectStatus.NoGroup;\n                return null;\n            }\n\n            projectStatus = ProjectStatus.Ok;\n\n            // Loop through each group\n            foreach (object group in groups)\n            {\n                if (group == null || addressableAssetGroupType == null || addressableAssetEntryType == null) continue;\n\n                // Get the group's 'entries' property\n                var entries = entriesProperty?.GetValue(group) as IEnumerable<object>;\n\n                if (entries == null) continue;\n\n                // Get the group's 'Name' property\n                var groupName = groupNameProperty?.GetValue(group)?.ToString();\n\n                // Loop through each entry in the group\n                foreach (object entry in entries)\n                {\n                    if (entry == null) continue;\n\n                    // Get the entry's 'address' and 'guid' properties\n                    var address = addressProperty?.GetValue(entry)?.ToString();\n                    var guid = guidProperty?.GetValue(entry)?.ToString();\n\n                    if (address == null || guid == null) continue;\n\n                    if (!addresses.TryGetValue(address, out AddressInfo fr2Address))\n                    {\n                        // New address entry\n                        fr2Address = new AddressInfo\n                        {\n                            address = address,\n                            bundleGroup = groupName,\n                            assetGUIDs = new HashSet<string>(),\n                            childGUIDs = new HashSet<string>()\n                        };\n\n                        addresses.Add(address, fr2Address);\n                    }\n\n                    if (fr2Address.assetGUIDs.Add(guid)) // folder?\n                    {\n                        AppendChildGUIDs(fr2Address.childGUIDs, guid);\n                    }\n                }\n            }\n\n            return addresses;\n        }\n\n        private static void AppendChildGUIDs(HashSet<string> h, string guid)\n        {\n            string folderPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (!AssetDatabase.IsValidFolder(folderPath)) return;\n            string[] allGUIDs = AssetDatabase.FindAssets(\"*\", new[] { folderPath });\n            foreach (string child in allGUIDs)\n            {\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(child, true);\n                if (asset == null)\n                {\n                    AssetFinderLOG.LogWarning($\"Why asset is null? {guid}\\n{folderPath}\");\n                    continue;\n                }\n                \n                if (asset.IsExcluded || asset.IsMissing || asset.IsScript || asset.type == AssetFinderAsset.AssetType.UNKNOWN) continue;\n                if (asset.inEditor || asset.inResources || asset.inStreamingAsset || asset.inPlugins) continue;\n                if (asset.extension == \".asmdef\") continue;\n                if (asset.extension == \".wlt\") continue;\n                if (asset.IsFolder) continue;\n                h.Add(child);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable/AssetFinderAddressable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 658fb11a3764f404881e3adcb3d9471d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Addressable.meta",
    "content": "fileFormatVersion: 2\nguid: ad6c77f8001445e78a614bfb210c5be1\ntimeCreated: 1746365309"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderCSV.cs",
    "content": "using System;\nusing System.Text;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderCSV\n    {\n        private const string SEPARATOR = \",\";\n        public static string GetCSVRow(AssetFinderRef r, params string[] suffixes)\n        {\n            AssetFinderAsset asset = r.asset;\n            AssetFinderSceneRef sr = r.isSceneRef ? (AssetFinderSceneRef)r : null;\n            var go = (GameObject)null;\n\n            if (sr != null)\n            {\n                if (sr.component is Component) go = ((Component)sr.component).gameObject;\n\n                if (sr.component is GameObject) go = (GameObject)sr.component;\n            }\n\n            var sb = new StringBuilder();\n\n            sb.Append(r.depth);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? sr.component.name : asset.assetName);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? AssetFinderRef.FindUsageScene(new[] { go }, false).Count : asset.UsageCount());\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? string.Empty : asset.extension);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? \"0\" : asset.fileSize.ToString());\n            sb.Append(SEPARATOR);\n\n            string type = r.isSceneRef ? \"SceneObject\" : \"(missing)\";\n            if (!r.isSceneRef)\n            {\n                Type obj = AssetDatabase.GetMainAssetTypeAtPath(asset.assetPath);\n                if (obj != null) type = obj.ToString();\n\n                if (type.StartsWith(\"UnityEngine.\") || type.StartsWith(\"UnityEditor.\"))\n                {\n                    int idx = type.LastIndexOf(\".\", StringComparison.Ordinal) + 1;\n                    type = type.Substring(idx, type.Length - idx);\n                }\n            }\n\n            sb.Append(type);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? string.Empty : asset.guid);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? string.Empty : asset.AtlasName);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? string.Empty : asset.AssetBundleName);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.group);\n            sb.Append(SEPARATOR);\n\n            sb.Append(r.isSceneRef ? sr.sceneFullPath : asset.assetPath);\n\n            foreach (string t in suffixes)\n            {\n                sb.Append(SEPARATOR);\n                sb.Append(t);\n            }\n\n            return sb.ToString();\n        }\n\n        public static string GetCSVTitle()\n        {\n            var sb = new StringBuilder();\n\n            sb.Append(\"depth\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"name\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"usage count\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"extension\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"size\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"type\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"guid\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"atlas\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"assetbundle\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"group\");\n            sb.Append(SEPARATOR);\n\n            sb.Append(\"full path\");\n\n            return sb.ToString();\n        }\n\n        public static string GetCSVRows(AssetFinderRef[] source)\n        {\n            if (source == null)\n\n                //Debug.LogWarning(\"source should not be null!\");\n            {\n                return string.Empty;\n            }\n\n            var sb = new StringBuilder();\n            sb.AppendLine(GetCSVTitle());\n            foreach (AssetFinderRef s in source)\n            {\n                if (s == null) continue;\n                sb.AppendLine(GetCSVRow(s));\n            }\n\n            return sb.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderCSV.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 64c9804c538c4e94ca30ab45cbd5cdc1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderExport.cs",
    "content": "//#define AssetFinderDEV\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderExport\n    {\n        private const int maxThread = 5;\n        private static Dictionary<string, ProcessReplaceData> listReplace;\n        private static HashSet<string> cacheSelection;\n\n\n        // private static List<Thread> lstThreads;\n        public static bool IsMergeProcessing { get; private set; }\n\n\n        public static void ExportCSV(AssetFinderRef[] csvSource)\n        {\n            string result = AssetFinderCSV.GetCSVRows(csvSource);\n            if (result.Length > 0)\n            {\n                EditorGUIUtility.systemCopyBuffer = result;\n                Debug.Log(\"[FR2] CSV file content (\" + csvSource.Length + \" assets) copied to clipboard!\");\n            } else\n            {\n                AssetFinderLOG.LogWarning(\"[FR2] Nothing to export!\");\n            }\n        }\n\n        #if AssetFinderDEV\n        [MenuItem(\"Assets/AssetFinder/Debug details\", false, 19)]\n        private static void DebugDetails()\n        {\n            var s = Selection.activeObject;\n            if (s == null) return;\n\n            var path = AssetDatabase.GetAssetPath(s);\n            if (string.IsNullOrEmpty(path))\n            {\n                AssetFinderLOG.LogWarning(\"Path: \" + path);\n                return;\n            }\n            \n            var guid = AssetDatabase.AssetPathToGUID(path);\n            var asset = AssetFinderCache.Api.Get(guid);\n            if (asset == null)\n            {\n                AssetFinderLOG.LogWarning($\"Asset is null??? {guid}\");\n                return;\n            }\n            \n            Debug.Log(asset.DebugUseGUID());\n        }\n        #endif\n\n        [MenuItem(\"Assets/AssetFinder/Toggle Ignore\", false, 19)]\n        private static void Ignore()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            Object[] actives = Selection.objects;\n            for (var i = 0; i < actives.Length; i++)\n            {\n                string path = AssetDatabase.GetAssetPath(actives[i]);\n                if (path.Equals(AssetFinderCache.DEFAULT_CACHE_PATH)) continue;\n\n                if (AssetFinderSetting.IgnoreAsset.Contains(path))\n                {\n                    AssetFinderSetting.RemoveIgnore(path);\n                } else\n                {\n                    AssetFinderSetting.AddIgnore(path);\n                }\n            }\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Copy GUID\", false, 20)]\n        private static void CopyGUID()\n        {\n            EditorGUIUtility.systemCopyBuffer = AssetDatabase.AssetPathToGUID(\n                AssetDatabase.GetAssetPath(Selection.activeObject)\n            );\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Export Selection\", false, 21)]\n        private static void ExportSelection()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            AssetFinderUnity.ExportSelection();\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Select Dependencies (assets I use)\", false, 22)]\n        private static void SelectDependencies_wtme()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            SelectDependencies(false);\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Refresh\")]\n        public static void ForceRefreshSelection()\n        {\n            string[] guids = Selection.assetGUIDs;\n            if (!AssetFinderCache.isReady) return; // cache not ready!\n\n            for (var i = 0; i < guids.Length; i++)\n            {\n                string guid = guids[i];\n                if (guid == AssetFinderCache.CachePath) continue;\n\n                if (!AssetFinderAsset.IsValidGUID(guid)) continue;\n\n                if (AssetFinderCache.Api.AssetMap.ContainsKey(guid))\n                {\n                    AssetFinderCache.Api.RefreshAsset(guid, true);\n#if AssetFinderDEBUG\n\t\t\t\tUnityEngine.Debug.Log(\"Changed : \" + guids[i]);\n#endif\n\n                    continue;\n                }\n\n                AssetFinderCache.Api.AddAsset(guid);\n            }\n\n            AssetFinderCache.Api.Check4Work();\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Select Dependencies included me\", false, 23)]\n        private static void SelectDependencies_wme()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            SelectDependencies(true);\n        }\n\n        //[MenuItem(\"Assets/AssetFinder/Select\")] \n        [MenuItem(\"Assets/AssetFinder/Select Used (assets used me)\", false, 24)]\n        private static void SelectUsed_wtme()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            SelectUsed(false);\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Select Used included me\", false, 25)]\n        private static void SelectUsed_wme()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            SelectUsed(true);\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Export Dependencies\", false, 40)]\n        private static void ExportDependencies()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            List<Object> deps = GetSelectionDependencies();\n            if (deps == null) return;\n\n            Selection.objects = deps.ToArray();\n            AssetFinderUnity.ExportSelection();\n        }\n\n        [MenuItem(\"Assets/AssetFinder/Export Assets (no scripts)\", false, 41)]\n        private static void ExportAsset()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"AssetFinder cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return;\n            }\n\n            List<Object> list = GetSelectionDependencies();\n\n            for (int i = list.Count - 1; i >= 0; i--)\n            {\n                if (list[i] is MonoScript) list.RemoveAt(i);\n            }\n\n            //Debug.Log(i + \":\" + list[i] + \":\" + list[i].GetType());\n            Selection.objects = list.ToArray();\n            AssetFinderUnity.ExportSelection();\n        }\n\n        public static void MergeDuplicate(string guid_file)\n        {\n            // for (int i = 0; i < Selection.objects.Length; i++)\n            // {\n            //     Object item = Selection.objects[i];\n            //     Debug.Log(item.name);\n            // }\n            //string guid_file = EditorGUIUtility.systemCopyBuffer;\n            long toFileId = 0;\n            string[] string_arr = guid_file.Split('/');\n            if (string_arr.Length > 1) toFileId = long.Parse(string_arr[1]);\n            string guid = string_arr[0];\n\n            // var wat = new System.Diagnostics.Stopwatch();\n            // wat.Start();\n            //validate clipboard guid\n\n            string gPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(gPath) || !gPath.StartsWith(\"Assets/\"))\n            {\n                AssetFinderLOG.LogWarning(\"Invalid guid <\" + guid + \"> in clipboard, can not replace !\");\n                return;\n            }\n\n            string[] temp = AssetFinderUnity.Selection_AssetGUIDs; //cheat refresh selection, DO NOT delete\n            HashSet<string> guids_files = AssetFinderUnity._Selection_AssetGUIDs;\n\n            var realKey = \"\";\n            foreach (string item in guids_files)\n            {\n                if (item.StartsWith(guid_file, StringComparison.Ordinal)) realKey = item;\n            }\n            if (string.IsNullOrEmpty(realKey))\n            {\n                Debug.LogWarning(\"Clipboard guid <\" + guid +\n                    \"> not found in Selection, you may not intentionally replace selection assets by clipboard guid\");\n\n                //\t\t\t\tforeach (var item in guids_files) {\n                //\t\t\t\t\tDebug.Log (\"item: \" + item);\n                //\t\t\t\t}\n                return;\n            }\n            guids_files.Remove(realKey);\n            cacheSelection = new HashSet<string>();\n            foreach (string item in cacheSelection)\n            {\n                cacheSelection.Add(item);\n            }\n            if (guids_files.Count == 0)\n            {\n                AssetFinderLOG.LogWarning(\"No new asset selected to replace, must select all duplications to replace\");\n                return;\n            }\n\n\n            //check asset type, only replace same type\n#if REPLACE_SAME_TYPE\n            var type1 = AssetDatabase.GetMainAssetTypeAtPath(gPath);\n            var importType1 = AssetImporter.GetAtPath(gPath);\n#endif\n\n\n            var assetList = new List<AssetFinderAsset>();\n            var lstFind = new List<string>();\n\n            foreach (string item in guids_files)\n            {\n                string[] arr = item.Split('/');\n                string g = arr[0];\n\n#if REPLACE_SAME_TYPE\n                var p2 = AssetDatabase.GUIDToAssetPath(g);\n                var type2 = AssetDatabase.GetMainAssetTypeAtPath(p2);\n\n                if(type1 != type2)\n                {\n                    AssetFinderLOG.LogWarning(\"Cannot replace asset: \" + p2 + \" becase difference type\");\n                    continue;\n                }\n                if(type1 == typeof(UnityEngine.Texture2D))\n                {\n                    var importType2 = AssetImporter.GetAtPath(p2) as TextureImporter;\n                    var textureImportType1 = importType1 as TextureImporter;\n                    if (importType2 == null || textureImportType1 == null)\n                    {\n                        AssetFinderLOG.LogWarning(\"Cannot replace asset: \" + p2 + \" becase difference type\");\n                        continue;\n                    }\n                    if(textureImportType1.textureType != importType2.textureType)\n                    {\n                        AssetFinderLOG.LogWarning(\"Cannot replace asset: \" + p2 + \" becase difference type\");\n                        continue;\n                    }\n                    if (textureImportType1.textureType == TextureImporterType.Sprite)\n                    {\n                        if (textureImportType1.spriteImportMode != importType2.spriteImportMode)\n                        {\n                            AssetFinderLOG.LogWarning(\"Cannot replace asset: \" + p2 + \" becase difference type\");\n                            continue;\n                        }\n                    }\n                    //Debug.Log(\"import type \" + mainImportType);\n                }\n                //Debug.Log(\"type: \" + mainType);\n#endif\n                lstFind.Add(g);\n            }\n\n            if (lstFind.Count == 0)\n            {\n                AssetFinderLOG.LogWarning(\"No new asset selected to replace, must select all duplications to replace\");\n                return;\n            }\n\n            assetList = AssetFinderCache.Api.FindAssets(lstFind.ToArray(), false);\n\n            //replace one by one\n            listReplace = new Dictionary<string, ProcessReplaceData>();\n            for (int i = assetList.Count - 1; i >= 0; i--)\n            {\n//                Debug.Log(\"FR2 Replace GUID : \" + assetList[i].guid + \" ---> \" + guid + \" : \" + assetList[i].UsedByMap.Count + \" assets updated\");\n\n                string fromId = assetList[i].guid;\n\n                List<AssetFinderAsset> arr = assetList[i].UsedByMap.Values.ToList();\n                for (var j = 0; j < arr.Count; j++)\n                {\n                    AssetFinderAsset a = arr[j];\n                    if (!listReplace.ContainsKey(a.assetPath)) listReplace.Add(a.assetPath, new ProcessReplaceData());\n\n                    listReplace[a.assetPath].datas.Add(new ReplaceData\n                    {\n                        from = fromId,\n                        to = guid,\n                        asset = a,\n                        toFileId = toFileId\n                    });\n                }\n            }\n\n            // foreach (KeyValuePair<string, ProcessReplaceData> item in listReplace)\n            // {\n            //     item.Value.processIndex = item.Value.datas.Count - 1;\n            // }\n\n            IsMergeProcessing = true;\n            EditorApplication.update -= ApplicationUpdate;\n            EditorApplication.update += ApplicationUpdate;\n\n            // for (var i = assetList.Count - 1; i >= 0; i--)\n            // {\n            //     // Debug.Log(\"FR2 Replace GUID : \" + assetList[i].guid + \" ---> \" + guid + \" : \" + assetList[i].UsedByMap.Count + \" assets updated\");\n            //     var from = assetList[i].guid;\n\n            //     var arr = assetList[i].UsedByMap.Values.ToList();\n            //     for (var j = 0; j < arr.Count; j ++)\n            //     {\n            //         var a = arr[j];\n            //         var result = a.ReplaceReference(from, guid);\n\n            //         if (result && !dictAsset.ContainsKey(a.guid))\n            //         {\n            //             dictAsset.Add(a.guid, 1);\n            //         }\n            //     }\n            // }\n            // Debug.Log(\"Time replace guid \" + wat.ElapsedMilliseconds);\n            // wat = new System.Diagnostics.Stopwatch();\n            // wat.Start();\n            // var listRefresh = dictAsset.Keys.ToList();\n            // for (var i = 0; i < listRefresh.Count; i++)\n            // {\n            //     AssetFinderCache.Api.RefreshAsset(listRefresh[i], true);\n            // }\n\n            // AssetFinderCache.Api.RefreshSelection();\n            // AssetFinderCache.Api.Check4Usage();\n            // AssetDatabase.Refresh();\n            // Debug.Log(\"Time replace guid \" + wat.ElapsedMilliseconds);\n        }\n\n        private static void ApplicationUpdate()\n        {\n            var isCompleted = true;\n            foreach (KeyValuePair<string, ProcessReplaceData> item in listReplace)\n            {\n                if (item.Value.processed) continue;\n                item.Value.processed = true;\n\n                for (var i = 0; i < item.Value.datas.Count; i++)\n                {\n                    ReplaceData a = item.Value.datas[i];\n                    a.isTerrian = a.asset.type == AssetFinderAsset.AssetType.TERRAIN;\n                    if (a.isTerrian)\n                    {\n                        a.terrainData = AssetDatabase.LoadAssetAtPath(a.asset.assetPath, typeof(Object)) as TerrainData;\n                    }\n                    a.isSucess = a.asset.ReplaceReference(a.from, a.to, a.toFileId, a.terrainData);\n\n                    if (a.isTerrian)\n                    {\n                        a.terrainData = null;\n                        AssetFinderUnity.UnloadUnusedAssets();\n                    }\n                }\n\n                isCompleted = false;\n                break;\n            }\n\n            if (!isCompleted) return;\n            foreach (KeyValuePair<string, ProcessReplaceData> item in listReplace)\n            {\n                List<ReplaceData> lst = item.Value.datas;\n                for (var i = 0; i < lst.Count; i++)\n                {\n                    ReplaceData data = lst[i];\n                    if (!data.isUpdated && data.isSucess)\n                    {\n                        data.isUpdated = true;\n                        if (data.isTerrian)\n                        {\n                            EditorUtility.SetDirty(data.terrainData);\n                            AssetDatabase.SaveAssets();\n                            data.terrainData = null;\n                            AssetFinderUnity.UnloadUnusedAssets();\n                        } else\n                        {\n                            try\n                            {\n                                AssetDatabase.ImportAsset(data.asset.assetPath, ImportAssetOptions.Default);\n                            } catch (Exception e)\n                            {\n                                AssetFinderLOG.LogWarning(data.asset.assetPath + \"\\n\" + e);\n                            }\n                        }\n                    }\n                }\n            }\n            var guidsRefreshed = new HashSet<string>();\n            EditorApplication.update -= ApplicationUpdate;\n            foreach (KeyValuePair<string, ProcessReplaceData> item in listReplace)\n            {\n                List<ReplaceData> lst = item.Value.datas;\n                for (var i = 0; i < lst.Count; i++)\n                {\n                    ReplaceData data = lst[i];\n                    if (data.isSucess && !guidsRefreshed.Contains(data.asset.guid))\n                    {\n                        guidsRefreshed.Add(data.asset.guid);\n                        AssetFinderCache.Api.RefreshAsset(data.asset.guid, true);\n                    }\n                }\n            }\n\n            // lstThreads = null;\n            listReplace = null;\n            AssetFinderCache.Api.RefreshSelection();\n            AssetFinderCache.Api.Check4Work();\n\n            AssetDatabase.Refresh();\n            IsMergeProcessing = false;\n        }\n\n\n        //[MenuItem(\"Assets/AssetFinder/Tools/Fix Model Import Material\")]\n        //public static void FixModelImportMaterial(){\n        //\tif (Selection.activeObject == null) return;\n        //\tCreatePrefabReplaceModel((GameObject)Selection.activeObject);\n        //}\n\n        //[MenuItem(\"GameObject/FR2/Paste Materials\", false, 10)]\n        //public static void PasteMaterials(){\n        //\tif (Selection.activeObject == null) return;\n\n        //\tvar r = Selection.activeGameObject.GetComponent<Renderer>();\n        //\tUndo.RecordObject(r, \"Replace Materials\");\n        //\tr.materials = model_materials;\n        //\tEditorUtility.SetDirty(r);\n        //}\n\n        //[MenuItem(\"GameObject/FR2/Copy Materials\", false, 10)]\n        //public static void CopyMaterials(){\n        //\tif (Selection.activeObject == null) return;\n        //\tvar r = Selection.activeGameObject.GetComponent<Renderer>();\n        //\tif (r == null) return;\n        //\tmodel_materials = r.sharedMaterials;\n        //}\n\n        //-------------------------- APIs ----------------------\n\n        private static void SelectDependencies(bool includeMe)\n        {\n            List<AssetFinderAsset> list = AssetFinderCache.Api.FindAssets(AssetFinderUnity.Selection_AssetGUIDs, false);\n            var dict = new Dictionary<string, Object>();\n\n            if (includeMe) AddToDict(dict, list.ToArray());\n\n            for (var i = 0; i < list.Count; i++)\n            {\n                AddToDict(dict, AssetFinderAsset.FindUsage(list[i]).ToArray());\n            }\n\n            Selection.objects = dict.Values.ToArray();\n        }\n\n        private static void SelectUsed(bool includeMe)\n        {\n            List<AssetFinderAsset> list = AssetFinderCache.Api.FindAssets(AssetFinderUnity.Selection_AssetGUIDs, false);\n            var dict = new Dictionary<string, Object>();\n\n            if (includeMe) AddToDict(dict, list.ToArray());\n\n            for (var i = 0; i < list.Count; i++)\n            {\n                AddToDict(dict, list[i].UsedByMap.Values.ToArray());\n            }\n\n            Selection.objects = dict.Values.ToArray();\n        }\n\n\n        //-------------------------- UTILS ---------------------\n\n        internal static void AddToDict(Dictionary<string, Object> dict, params AssetFinderAsset[] list)\n        {\n            for (var j = 0; j < list.Length; j++)\n            {\n                string guid = list[j].guid;\n                if (!dict.ContainsKey(guid))\n                {\n                    string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n                    dict.Add(guid, AssetFinderUnity.LoadAssetAtPath<Object>(assetPath));\n                }\n            }\n        }\n\n        private static List<Object> GetSelectionDependencies()\n        {\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"FR2 cache not yet ready, please open Window > AssetFinderWindow and hit scan project!\");\n                return null;\n            }\n\n            return AssetFinderCache.FindUsage(AssetFinderUnity.Selection_AssetGUIDs).Select(\n                guid =>\n                {\n                    string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n                    return AssetFinderUnity.LoadAssetAtPath<Object>(assetPath);\n                }\n            ).ToList();\n        }\n\n        private class ProcessReplaceData\n        {\n            public readonly List<ReplaceData> datas = new List<ReplaceData>();\n            public bool processed;\n        }\n\n        private class ReplaceData\n        {\n            public AssetFinderAsset asset;\n            public string from;\n            public bool isSucess;\n            public bool isTerrian;\n            public bool isUpdated;\n            public TerrainData terrainData;\n            public string to;\n\n            public long toFileId;\n        }\n\n        //\tAssetDatabase.ImportAsset(oAssetPath, ImportAssetOptions.Default);\n        //\timporter.importMaterials = false;\n        //\tvar importer = AssetImporter.GetAtPath(oAssetPath) as ModelImporter;\n        //\tvar nModel = AssetDatabase.LoadAssetAtPath<GameObject>(oAssetPath);\n\n        //\t// Reimport model with importMaterial = false\n        //\tvar extension = Path.GetExtension(oAssetPath);\n\n        //\tmodel_materials = model.GetComponent<Renderer>().sharedMaterials;\n        //\tvar oGUID = AssetDatabase.AssetPathToGUID(oAssetPath);\n\n        //\tvar oAssetPath = AssetDatabase.GetAssetPath(model);\n        //\tif (model == null) return;\n        //{\n        //static void CreatePrefabReplaceModel(GameObject model)\n\n        //static Material[] model_materials;\n\n        //\t//create prefab from new model\n        //\tvar prefabPath = oAssetPath.Replace(extension, \".prefab\");\n        //\tvar clone = (GameObject)Object.Instantiate(nModel);\n        //\tclone.GetComponent<Renderer>().sharedMaterials = model_materials;\n        //\tPrefabUtility.CreatePrefab(prefabPath, clone, ReplacePrefabOptions.ReplaceNameBased);\n        //\tAssetDatabase.SaveAssets();\n        //\tGameObject.DestroyImmediate(clone);\n        //}\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderExport.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7450fa14644448c4a896cc7247ae1c02\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSceneCache.cs",
    "content": "#if UNITY_2018_3_OR_NEWER\n#define SUPPORT_NESTED_PREFAB\n#endif\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\n#if UNITY_2017_1_OR_NEWER\nusing UnityEditor.SceneManagement;\nusing UnityEngine.SceneManagement;\n#endif\n\n#if SUPPORT_NESTED_PREFAB\nusing UnityEditor.Experimental.SceneManagement;\n#endif\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class SceneRefInfo : IEquatable<SceneRefInfo>\n    {\n        public Component sourceComponent;\n        public Object target;\n        public string propertyPath;\n        public bool isSceneObject;\n        \n        public bool IsBackwardRef => target != null && sourceComponent != null;\n        public Object GetTargetComponent() => target;\n        public GameObject GetGameObjectFromTarget()\n        {\n            if (!target) return null;\n            if (target is GameObject go) return go;\n            if (target is Component comp && comp != null) return comp.gameObject;\n            return null;\n        }\n        \n        public bool Equals(SceneRefInfo other)\n        {\n            if (other == null) return false;\n            return sourceComponent == other.sourceComponent && \n                   target == other.target && \n                   propertyPath == other.propertyPath;\n        }\n        \n        public override bool Equals(object obj)\n        {\n            return obj is SceneRefInfo other && Equals(other);\n        }\n        \n        public override int GetHashCode()\n        {\n            unchecked\n            {\n                int hash = sourceComponent?.GetHashCode() ?? 0;\n                hash = hash * 31 + (target?.GetHashCode() ?? 0);\n                hash = hash * 31 + (propertyPath?.GetHashCode() ?? 0);\n                return hash;\n            }\n        }\n    }\n\n    internal enum SceneCacheStatus\n    {\n        None,       // Never initialized (default state)\n        Changed,    // Needs refresh\n        Scanning,   // Currently scanning\n        Ready       // Ready for use\n    }\n\n    [Flags]\n    internal enum SceneChangeFlags\n    {\n        None = 0,\n        SceneReset = 1,        // Scene unloaded/reloaded or new scene opened\n        SceneModify = 2,       // Objects modified (from Undo system)\n        SceneAdditive = 4,     // Prefab stage or multi-scene changes\n        UserRefresh = 8        // User-requested full refresh\n    }\n\n    internal class AssetFinderSceneCache\n    {\n        private static AssetFinderSceneCache _api;\n        public static Action onReady;\n        \n        private SceneCacheStatus _status = SceneCacheStatus.None;\n        private Dictionary<Component, HashSet<HashValue>> _cache = new Dictionary<Component, HashSet<HashValue>>();\n        private bool _isDirty;\n        private SceneChangeFlags _changeFlags = SceneChangeFlags.None;\n        private readonly HashSet<int> _modifiedInstanceIds = new HashSet<int>();\n        private bool _autoRefresh;\n        private float _lastDirtyTime;\n        private const float DIRTY_DEBOUNCE_TIME = 0.1f; // 100ms debounce\n        \n        public int current;\n        private List<GameObject> listGO;\n\n        //public HashSet<string> prefabDependencies = new HashSet<string>();\n        public Dictionary<GameObject, HashSet<string>> prefabDependencies =\n            new Dictionary<GameObject, HashSet<string>>();\n        \n        public int total;\n\n        public AssetFinderSceneCache()\n        {\n            // Register for Unity hierarchy change events\n            // Note: Multiple events are registered to catch different types of scene changes\n#if UNITY_2018_1_OR_NEWER\n            EditorApplication.hierarchyChanged -= OnSceneChanged;\n            EditorApplication.hierarchyChanged += OnSceneChanged;\n#else\n\t\t\tEditorApplication.hierarchyWindowChanged -= OnSceneChanged;\n\t\t\tEditorApplication.hierarchyWindowChanged += OnSceneChanged;\n#endif\n\n#if UNITY_2018_2_OR_NEWER\n            EditorSceneManager.activeSceneChangedInEditMode -= OnSceneChanged;\n            EditorSceneManager.activeSceneChangedInEditMode += OnSceneChanged;\n#endif\n\n#if UNITY_2017_1_OR_NEWER\n            SceneManager.activeSceneChanged -= OnSceneChanged;\n            SceneManager.activeSceneChanged += OnSceneChanged;\n\n            SceneManager.sceneLoaded -= OnSceneChanged;\n            SceneManager.sceneLoaded += OnSceneChanged;\n\n            Undo.postprocessModifications -= OnModify;\n            Undo.postprocessModifications += OnModify;\n#endif\n\n            // Add play mode detection\n            EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;\n            EditorApplication.playModeStateChanged += OnPlayModeStateChanged;\n\n            // Initialize auto-refresh from settings\n            _autoRefresh = AssetFinderSettingExt.isAutoRefreshEnabled;\n        }\n\n        public static bool hasCache => _api != null && (_api._status == SceneCacheStatus.Ready || _api._status == SceneCacheStatus.Changed);\n        \n        public static AssetFinderSceneCache Api\n        {\n            get\n            {\n                if (_api != null) return _api;\n                _api = new AssetFinderSceneCache();\n                return _api;\n            }\n        }\n\n        public static bool isReady => (_api != null && _api._status == SceneCacheStatus.Ready);\n        public static bool hasInit => (_api != null && _api._status != SceneCacheStatus.None);\n        \n        public SceneCacheStatus Status\n        {\n            get => _status;\n            set => _status = value;\n        }\n\n        public Dictionary<Component, HashSet<HashValue>> cache\n        {\n            get\n            {\n                if (_cache == null) RefreshCache(false);\n                return _cache;\n            }\n        }\n\n        public bool Dirty\n        {\n            get => _isDirty;\n            set => _isDirty = value;\n        }\n\n        public bool AutoRefresh\n        {\n            get => _autoRefresh;\n            set => _autoRefresh = value;\n        }\n\n        public void RefreshCache(bool force)\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating)\n            {\n                AssetFinderLOG.Log($\"refreshCache skipped: isCompiling: {EditorApplication.isCompiling} / isUpdating: {EditorApplication.isUpdating}\");\n                \n                SetDirty();\n                return;\n            }\n            \n            if (_status == SceneCacheStatus.Scanning) \n            {\n                AssetFinderLOG.Log($\"refreshCache skipped - already scanning\");\n                return; // Prevent re-entrance\n            }\n            \n            // User refresh always forces full scan\n            if (force || (_changeFlags & SceneChangeFlags.UserRefresh) != 0)\n            {\n                PerformFullRefresh();\n                return;\n            }\n            \n            if (!_autoRefresh)\n            {\n                #if AssetFinderDEBUG\n                Debug.Log($\"refreshCache: skipped - autoRefresh == false (but still dirty)\");\n                #endif\n                \n                _isDirty = true;\n                _status =  SceneCacheStatus.Changed;\n                return;\n            } \n            \n            // if (_status == SceneCacheStatus.None || _status == SceneCacheStatus.Changed)\n            // {\n            //     Debug.Log($\"refreshCache: start scanning\");\n            // }\n            \n            // Check if scan is needed\n            bool needsScan = _isDirty || _cache.Count == 0 || _changeFlags != SceneChangeFlags.None;\n            if (!needsScan)\n            {\n                AssetFinderLOG.Log($\"refreshCache: skipped - do not needScan\");\n                _status = SceneCacheStatus.Ready;\n                return;\n            }\n            \n            if ((_changeFlags & SceneChangeFlags.SceneReset) != 0)\n            {\n                PerformFullRefresh();\n                return;\n            }\n            \n            PerformIncrementalRefresh();\n        }\n\n        private void PerformFullRefresh()\n        {\n            _status = SceneCacheStatus.Scanning;\n            _isDirty = false;\n            current = 0;\n            total = 0;\n            \n            _cache = new Dictionary<Component, HashSet<HashValue>>();\n            prefabDependencies = new Dictionary<GameObject, HashSet<string>>();\n            _modifiedInstanceIds.Clear();\n            _changeFlags = SceneChangeFlags.None;\n\n            List<GameObject> listRootGO = null;\n\n#if SUPPORT_NESTED_PREFAB\n            if (PrefabStageUtility.GetCurrentPrefabStage() != null)\n            {\n                GameObject rootPrefab = PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot;\n                if (rootPrefab != null) listRootGO = new List<GameObject> { rootPrefab };\n            }\n#endif\n            if (listRootGO == null)\n            {\n                listGO = AssetFinderUnity.getAllObjsInCurScene().ToList();\n            } else\n            {\n                listGO = new List<GameObject>();\n                foreach (GameObject item in listRootGO)\n                {\n                    listGO.AddRange(AssetFinderUnity.getAllChild(item, true));\n                }\n            }\n\n            // Set total as work count (objects to scan) and freeze it during scan\n            total = listGO.Count;\n            current = 0;\n            \n            if (total == 0 || total == current)\n            {\n                Dirty = false;\n                _status = SceneCacheStatus.Ready;\n                onReady?.Invoke();\n                return;\n            }\n            \n            AssetFinderLOG.Log($\"Register OnUpdate: {nameof(PerformFullRefresh)}\");\n            EditorApplication.update -= OnUpdate;\n            EditorApplication.update += OnUpdate;\n        }\n\n        private void PerformIncrementalRefresh()\n        {\n            // AssetFinderLOG.Log(\"PerformIncrementalRefresh!\");\n            \n            _isDirty = false;\n            _status = SceneCacheStatus.Scanning;\n            current = 0;\n            total = 0;\n            \n            // Clean up invalid cache entries\n            var keysToRemove = new List<Component>();\n            foreach (var kvp in _cache)\n            {\n                if (kvp.Key == null || kvp.Key.gameObject == null)\n                {\n                    keysToRemove.Add(kvp.Key);\n                }\n            }\n            \n            foreach (var key in keysToRemove)\n            {\n                _cache.Remove(key);\n            }\n\n            // Get objects that need scanning (modified + new ones)\n            var currentObjects = new HashSet<int>();\n            List<GameObject> allObjects;\n\n#if SUPPORT_NESTED_PREFAB\n            if (PrefabStageUtility.GetCurrentPrefabStage() != null)\n            {\n                GameObject rootPrefab = PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot;\n                allObjects = rootPrefab != null ? AssetFinderUnity.getAllChild(rootPrefab, true).ToList() : new List<GameObject>();\n            }\n            else\n#endif\n            {\n                allObjects = AssetFinderUnity.getAllObjsInCurScene().ToList();\n            }\n\n            foreach (var go in allObjects)\n            {\n                if (go != null) currentObjects.Add(go.GetInstanceID());\n            }\n\n            // Find objects to scan (modified or new)\n            listGO = new List<GameObject>();\n            foreach (var go in allObjects)\n            {\n                if (go == null) continue;\n                \n                int instanceId = go.GetInstanceID();\n                bool isModified = _modifiedInstanceIds.Contains(instanceId);\n                bool isNew = !_cache.Keys.Any(comp => comp != null && comp.gameObject != null && comp.gameObject.GetInstanceID() == instanceId);\n                \n                if (isModified || isNew)\n                {\n                    listGO.Add(go);\n                }\n            }\n\n            // Set total as work count (objects to scan) and freeze it during scan\n            total = listGO.Count;\n            current = 0;\n            _modifiedInstanceIds.Clear();\n            _changeFlags = SceneChangeFlags.None;\n            \n            if (total == 0 || current >= total)\n            {\n                _status = SceneCacheStatus.Ready;\n                if (onReady != null) onReady();\n                return;\n            }\n            \n            #if AssetFinderDEBUG\n            Debug.Log($\"Register OnUpdate: {nameof(PerformIncrementalRefresh)} | {current}/{total}\");\n            #endif\n            \n            EditorApplication.update -= OnUpdate;\n            EditorApplication.update += OnUpdate;\n            Dirty = false;\n        }\n        \n        private void OnUpdate()\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating)\n            {\n                StopScanning(SceneCacheStatus.None);\n                return;\n            }\n            \n            for (var i = 0; i < 5 * AssetFinderCache.priority; i++)\n            {\n                if (listGO == null || listGO.Count <= 0) break;\n                var index = listGO.Count - 1;\n                var go = listGO[index];\n                if (go == null) \n                {\n                    listGO.RemoveAt(index);\n                    current++;\n                    continue;\n                }\n\n                // Remove existing cache entries for this GameObject\n                var componentsToRemove = _cache.Keys.Where(comp => comp != null && comp.gameObject == go).ToList();\n                foreach (var comp in componentsToRemove)\n                {\n                    _cache.Remove(comp);\n                }\n\n                string prefabGUID = AssetFinderUnity.GetPrefabParent(go);\n                if (!string.IsNullOrEmpty(prefabGUID))\n                {\n                    Transform parent = go.transform.parent;\n                    while (parent != null)\n                    {\n                        GameObject g = parent.gameObject;\n                        if (!prefabDependencies.ContainsKey(g)) prefabDependencies.Add(g, new HashSet<string>());\n\n                        prefabDependencies[g].Add(prefabGUID);\n                        parent = parent.parent;\n                    }\n                }\n\n                Component[] components = go.GetComponents<Component>();\n\n                foreach (Component com in components)\n                {\n                    if (com == null) continue;\n\n                    var serialized = new SerializedObject(com);\n                    SerializedProperty it = serialized.GetIterator().Copy();\n                    while (it.Next(true))\n                    {\n                        if (it.propertyType != SerializedPropertyType.ObjectReference) continue;\n\n                        if (it.objectReferenceValue == null) continue;\n                        bool isSceneObject = it.objectReferenceValue.IsSceneObject();\n                        if (!_cache.ContainsKey(com)) _cache.Add(com, new HashSet<HashValue>());\n\n                        _cache[com].Add(new HashValue\n                            { target = it.objectReferenceValue, isSceneObject = isSceneObject, propertyPath = it.propertyPath });\n                    }\n                }\n\n                listGO.RemoveAt(index);\n                current++;\n            }\n\n            if (listGO != null && listGO.Count > 0) return; // to be continue\n            \n            Dirty = false;\n            StopScanning(SceneCacheStatus.Ready);\n            onReady?.Invoke();\n        }\n\n        private void OnPlayModeStateChanged(PlayModeStateChange state)\n        {\n            switch (state)\n            {\n                case PlayModeStateChange.EnteredPlayMode:\n                    StopScanning(SceneCacheStatus.None);\n                    break;\n                    \n                case PlayModeStateChange.ExitingPlayMode:\n                    SetDirty();\n                    break;\n                    \n                case PlayModeStateChange.EnteredEditMode:\n                    if (_autoRefresh)\n                    {\n                        _changeFlags |= SceneChangeFlags.SceneReset;\n                        SetDirty();\n                        EditorApplication.delayCall += () => RefreshCache(false);\n                    }\n                    break;\n            }\n        }\n\n        private void OnSceneChanged()\n        {\n            // In play mode, avoid unnecessary dirty marking when auto-refresh is disabled\n            if (Application.isPlaying)\n            {\n                // Only mark dirty if auto-refresh is enabled, otherwise it's pointless\n                if (_autoRefresh)\n                {\n                    #if AssetFinderDEBUG\n                    Debug.LogWarning($\"Set dirty: {nameof(OnSceneChanged)} - Play Mode with AutoRefresh\");\n                    #endif\n                    SetDirty();\n                }\n                return;\n            }\n            \n            // Check if we're in prefab mode - don't treat prefab mode changes as scene changes\n#if SUPPORT_NESTED_PREFAB\n            bool isInPrefabMode = PrefabStageUtility.GetCurrentPrefabStage() != null;\n            if (isInPrefabMode)\n            {\n                #if AssetFinderDEBUG\n                Debug.LogWarning($\"Set dirty: {nameof(isInPrefabMode)}\");\n                #endif\n                \n                // Properly mark as dirty and update status\n                SetDirty();\n                _changeFlags |= SceneChangeFlags.SceneAdditive;\n                \n                // Always perform incremental refresh in prefab mode\n                // because the scene/prefab hierarchy has changed\n                PerformIncrementalRefresh();\n                return;\n            }\n#endif\n            \n            // Detect if this is a scene unload vs hierarchy change\n            List<GameObject> currentObjects = AssetFinderUnity.getAllObjsInCurScene().ToList();\n            \n            // If no objects in scene, it's likely a scene unload - just clean cache without refresh\n            if (currentObjects.Count == 0)\n            {\n                _cache.Clear();\n                prefabDependencies.Clear();\n                _modifiedInstanceIds.Clear();\n                _changeFlags = SceneChangeFlags.None;\n                _status = SceneCacheStatus.Ready;\n                _isDirty = false;\n                return;\n            }\n            \n            // Check for new GameObjects (cloning/duplication)\n            var existingIds = new HashSet<int>();\n            foreach (var comp in _cache.Keys)\n            {\n                if (comp != null && comp.gameObject != null)\n                {\n                    existingIds.Add(comp.gameObject.GetInstanceID());\n                }\n            }\n            \n            bool hasNewObjects = false;\n            foreach (var go in currentObjects)\n            {\n                if (go != null && !existingIds.Contains(go.GetInstanceID()))\n                {\n                    hasNewObjects = true;\n                    _modifiedInstanceIds.Add(go.GetInstanceID());\n                }\n            }\n            \n            // Use incremental refresh for new objects, full refresh for major changes\n            if (hasNewObjects && _cache.Count > 0)\n            {\n                _changeFlags |= SceneChangeFlags.SceneModify;\n            }\n            else\n            {\n                _changeFlags |= SceneChangeFlags.SceneAdditive;\n            }\n            \n            SetDirty();\n            \n            // Only auto-refresh if auto refresh is enabled and not currently scanning\n            if (_autoRefresh && _status != SceneCacheStatus.Scanning)\n            {\n                Api.RefreshCache(false);\n            }\n        }\n\n#if UNITY_2017_1_OR_NEWER\n        private UndoPropertyModification[] OnModify(UndoPropertyModification[] modifications)\n        {\n            bool hasRelevantChange = false;\n            \n            for (var i = 0; i < modifications.Length; i++)\n            {\n                var mod = modifications[i];\n                \n                // Only mark dirty for object reference changes in scene objects\n                if (mod.currentValue.objectReference != null || mod.previousValue.objectReference != null)\n                {\n                    var target = mod.currentValue.target ?? mod.previousValue.target;\n                    if (target != null && !EditorUtility.IsPersistent(target))\n                    {\n                        hasRelevantChange = true;\n                        _modifiedInstanceIds.Add(target.GetInstanceID());\n                        \n                        // Also mark the GameObject if target is a component\n                        if (target is Component comp && comp.gameObject != null)\n                        {\n                            _modifiedInstanceIds.Add(comp.gameObject.GetInstanceID());\n                        }\n                    }\n                }\n            }\n\n            if (hasRelevantChange)\n            {\n                _changeFlags |= SceneChangeFlags.SceneModify;\n                SetDirty();\n            }\n\n            return modifications;\n        }\n#endif\n\n        public void SetDirty()\n        {\n            // Debounce rapid SetDirty calls to prevent unnecessary dirty marking\n            float currentTime = Time.realtimeSinceStartup;\n            if (currentTime - _lastDirtyTime < DIRTY_DEBOUNCE_TIME && _isDirty)\n            {\n                return; // Skip if already dirty and within debounce time\n            }\n            \n            _lastDirtyTime = currentTime;\n            \n            if (_status == SceneCacheStatus.None || _status == SceneCacheStatus.Ready)\n            {\n                _status = SceneCacheStatus.Changed;\n            }\n            _isDirty = true;\n        }\n\n        public void ForceRefresh()\n        {\n            _changeFlags |= SceneChangeFlags.UserRefresh;\n            SetDirty();\n            RefreshCache(true);\n        }\n\n        private void StopScanning(SceneCacheStatus updatedStatus)\n        {\n            // Debug.Log($\"StopScanning: {current} / {total} | {_status}\");\n            EditorApplication.update -= OnUpdate;\n            _status = updatedStatus;\n            listGO = null;\n            current = 0;\n            total = 0;\n        }\n        \n\n        public static Dictionary<string, AssetFinderRef> FindSceneUseSceneObjects(GameObject[] targets)\n        {\n            var results = new Dictionary<string, AssetFinderRef>();\n            \n            foreach (var selectedGO in targets)\n            {\n                if (selectedGO == null || selectedGO.IsAssetObject()) continue;\n\n                var key = selectedGO.GetInstanceID().ToString();\n                if (!results.ContainsKey(key)) \n                {\n                    results.Add(key, new AssetFinderSceneRef(0, selectedGO));\n                }\n\n                ScanForwardReferences(selectedGO, results);\n            }\n\n            return results;\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindSceneBackwardReferences(GameObject[] targets)\n        {\n            var results = new Dictionary<string, AssetFinderRef>();\n            \n            foreach (var selectedGO in targets)\n            {\n                if (selectedGO.IsAssetObject()) continue;\n                \n                var key = selectedGO.GetInstanceID().ToString();\n                if (!results.ContainsKey(key))\n                {\n                    results.Add(key, new AssetFinderSceneRef(0, selectedGO));\n                }\n            }\n            \n            ScanBackwardReferences(targets.Where(t => t != null).ToHashSet(), results);\n            return results;\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindSceneInScene(GameObject[] targets)\n        {\n            var results = new Dictionary<string, AssetFinderRef>();\n            \n            foreach (var obj in targets)\n            {\n                if (obj == null || obj.IsAssetObject()) continue;\n                var key = obj.GetInstanceID().ToString();\n                if (!results.ContainsKey(key)) results.Add(key, new AssetFinderSceneRef(0, obj));\n            }\n\n            ScanSceneInScene(targets, results);\n            return results;\n        }\n\n        private static void ScanForwardReferences(GameObject selectedGO, Dictionary<string, AssetFinderRef> results)\n        {\n            if (selectedGO == null) return;\n\n            var sceneCache = Api.cache;\n            var components = selectedGO.GetComponents<Component>();\n            \n            for (var i = 0; i < components.Length; i++)\n            {\n                var com = components[i];\n                if (com == null || com is Transform) continue;\n                \n                if (!sceneCache.TryGetValue(com, out var hashValues)) continue;\n                \n                foreach (var hashValue in hashValues)\n                {\n                    if (hashValue.target == null || !hashValue.isSceneObject) continue;\n                    \n                    var targetGO = GetGameObjectFromTarget(hashValue.target);\n                    if (targetGO == null || targetGO == selectedGO) continue;\n\n                    var targetKey = hashValue.target.GetInstanceID().ToString();\n                    if (!results.ContainsKey(targetKey)) \n                    {\n                        var tRef = new AssetFinderSceneRef(1, hashValue.target)\n                        {\n                            sourceRefs = new List<SceneRefInfo>()\n                        };\n                        results.Add(targetKey, tRef);\n                    }\n\n                    var targetRef = results[targetKey] as AssetFinderSceneRef;\n                    targetRef.sourceRefs.Add(new SceneRefInfo\n                    {\n                        sourceComponent = com,\n                        target = hashValue.target,\n                        propertyPath = hashValue.propertyPath,\n                        isSceneObject = hashValue.isSceneObject\n                    });\n                }\n            }\n        }\n\n        private static void ScanBackwardReferences(HashSet<GameObject> selectedGameObjects, Dictionary<string, AssetFinderRef> results)\n        {\n            var sceneCache = Api.cache;\n            \n            foreach (var cacheEntry in sceneCache)\n            {\n                var sourceComponent = cacheEntry.Key;\n                if (sourceComponent == null || sourceComponent.gameObject == null || typeof(Transform).IsAssignableFrom(sourceComponent.GetType())) continue;\n                \n                var sourceGO = sourceComponent.gameObject;\n                if (sourceGO == null || selectedGameObjects.Contains(sourceGO)) continue;\n                \n                foreach (var hashValue in cacheEntry.Value)\n                {\n                    if (hashValue.target == null || !hashValue.isSceneObject) continue;\n                    \n                    var targetGO = GetGameObjectFromTarget(hashValue.target);\n                    if (targetGO == null || targetGO == sourceGO || !selectedGameObjects.Contains(targetGO)) continue;\n\n                    var sourceKey = sourceGO.GetInstanceID().ToString();\n                    if (!results.ContainsKey(sourceKey))\n                    {\n                        var sourceRef = new AssetFinderSceneRef(1, sourceGO);\n                        sourceRef.backwardRefs = new List<SceneRefInfo>();\n                        results.Add(sourceKey, sourceRef);\n                    }\n                        \n                    var backwardRef = results[sourceKey] as AssetFinderSceneRef;\n                    backwardRef.backwardRefs.Add(new SceneRefInfo\n                    {\n                        sourceComponent = sourceComponent,\n                        target = hashValue.target,\n                        propertyPath = hashValue.propertyPath,\n                        isSceneObject = hashValue.isSceneObject\n                    });\n                }\n            }\n        }\n\n        private static void ScanSceneInScene(GameObject[] objs, Dictionary<string, AssetFinderRef> results)\n        {\n            var sceneCache = Api.cache;\n            \n            foreach (var cacheEntry in sceneCache)\n            {\n                var sourceComponent = cacheEntry.Key;\n                if (sourceComponent == null || sourceComponent.gameObject == null || typeof(Transform).IsAssignableFrom(sourceComponent.GetType())) continue;\n                \n                foreach (var hashValue in cacheEntry.Value)\n                {\n                    if (hashValue.target == null) continue;\n                    var targetGO = GetGameObjectFromTarget(hashValue.target);\n                    if (targetGO == null || sourceComponent.gameObject == targetGO) continue;\n\n                    foreach (var obj in objs)\n                    {\n                        if (obj == null || targetGO != obj) continue;\n\n                        var key = sourceComponent.GetInstanceID().ToString();\n                        if (!results.ContainsKey(key)) \n                        {\n                            var sourceRef = new AssetFinderSceneRef(1, sourceComponent)\n                            {\n                                backwardRefs = new List<SceneRefInfo>()\n                            };\n                            results.Add(key, sourceRef);\n                        }\n\n                        var backwardRef = results[key] as AssetFinderSceneRef;\n                        backwardRef.backwardRefs.Add(new SceneRefInfo\n                        {\n                            sourceComponent = sourceComponent,\n                            target = hashValue.target,\n                            propertyPath = hashValue.propertyPath,\n                            isSceneObject = hashValue.isSceneObject\n                        });\n                        break;\n                    }\n                }\n            }\n        }\n\n        private static GameObject GetGameObjectFromTarget(Object target)\n        {\n            if (!target) return null;\n            if (target is GameObject go) return go;\n            if (target is Component comp && comp) return comp.gameObject;\n            return null;\n        }\n\n        internal class HashValue : IEquatable<HashValue>\n        {\n            // original fields – DO NOT RENAME\n            public bool isSceneObject;\n            public Object target;\n            public string propertyPath;\n\n            // --------- value equality ---------\n            public bool Equals(HashValue other)\n            {\n                if (ReferenceEquals(other, null)) return false;\n                if (ReferenceEquals(this,  other)) return true;\n\n                return isSceneObject == other.isSceneObject &&\n                    target        == other.target &&          // Unity overloads ==\n                    propertyPath  == other.propertyPath;\n            }\n\n            public override bool Equals(object obj) => Equals(obj as HashValue);\n\n            public override int GetHashCode()\n            {\n                unchecked\n                {\n                    int hash = 17;\n                    hash = hash * 23 + isSceneObject.GetHashCode();\n                    hash = hash * 23 + (target ? target.GetInstanceID() : 0);\n                    hash = hash * 23 + (propertyPath?.GetHashCode() ?? 0);\n                    return hash;\n                }\n            }\n\n            public static bool operator ==(HashValue a, HashValue b) => Equals(a, b);\n            public static bool operator !=(HashValue a, HashValue b) => !Equals(a, b);\n        }\n\n#if UNITY_2017_1_OR_NEWER\n        private void OnSceneChanged(Scene scene, LoadSceneMode mode)\n        {\n            OnSceneChanged();\n        }\n\n        private void OnSceneChanged(Scene arg0, Scene arg1)\n        {\n            OnSceneChanged();\n        }\n#endif\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSceneCache.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9207f99b6216de54299cf88ed80e86a3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSelection.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderSelection : IRefDraw\n    {\n        internal readonly AssetFinderRefDrawer drawer;\n        internal readonly HashSet<string> guidSet = new HashSet<string>();\n        internal readonly HashSet<string> instSet = new HashSet<string>(); // Do not reference directly to SceneObject (which might be destroyed anytime)\n\n        // ------------ instance\n\n        private bool dirty;\n        internal bool isLock;\n        internal Dictionary<string, AssetFinderRef> refs;\n\n        public AssetFinderSelection(IWindow window, Func<AssetFinderRefDrawer.Sort> getSortMode, Func<AssetFinderRefDrawer.Mode> getGroupMode)\n        {\n            this.window = window;\n            drawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = window,\n                getSortMode = getSortMode,\n                getGroupMode = getGroupMode,\n                showFullPath = false,\n                showFileSize = false,\n                showExtension = true,\n                showUsageType = false,\n                showAssetBundleName = false,\n                showAtlasName = false,\n                showToggle = false,\n                shouldShowExtension = () => true, // Selection panel always shows extensions\n                shouldShowDetailButton = () => false, // Selection panel never shows detail buttons\n                onCacheInvalidated = () => { } // Selection panel doesn't need cache invalidation\n            })\n            {\n                groupDrawer = { hideGroupIfPossible = true },\n                level0Group = string.Empty,\n                paddingLeft = -16f\n            };\n\n            dirty = true;\n            drawer.SetDirty();\n        }\n\n        public int Count => guidSet.Count + instSet.Count;\n\n        public bool isSelectingAsset => guidSet.Count > 0 && instSet.Count == 0;\n        public bool isSelectingSceneObject => instSet.Count > 0 && guidSet.Count == 0;\n\n        public IWindow window { get; set; }\n\n        public int ElementCount()\n        {\n            return refs?.Count ?? 0;\n        }\n\n        public bool DrawLayout()\n        {\n            if (dirty) RefreshView();\n            return drawer.DrawLayout();\n        }\n\n        public bool Draw(Rect rect)\n        {\n            if (dirty) RefreshView();\n            if (refs == null) return false;\n            rect.yMax -= 16f;\n            return drawer.Draw(rect);\n        }\n\n        public void Add(UnityObject sceneObject)\n        {\n            if (sceneObject == null) return;\n            var id = sceneObject.GetInstanceID().ToString();\n            instSet.Add(id);\n            dirty = true;\n        }\n\n        public void Add(string guid)\n        {\n            if (guidSet.Contains(guid)) return;\n            string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(assetPath))\n            {\n                AssetFinderLOG.LogWarning(\"Invalid GUID: \" + guid);\n                return;\n            }\n\n            guidSet.Add(guid);\n            dirty = true;\n        }\n\n        public void AddRange(params string[] guids)\n        {\n            foreach (string id in guids)\n            {\n                Add(id);\n            }\n            dirty = true;\n        }\n\n        public void Remove(UnityObject sceneObject)\n        {\n            if (sceneObject == null) return;\n            var id = sceneObject.GetInstanceID().ToString();\n            instSet.Remove(id);\n            dirty = true;\n        }\n\n        public void Remove(string guidOrInstID)\n        {\n            guidSet.Remove(guidOrInstID);\n            instSet.Remove(guidOrInstID);\n\n            dirty = true;\n        }\n\n        public void Clear()\n        {\n            guidSet.Clear();\n            instSet.Clear();\n            dirty = true;\n        }\n\n        public void Add(AssetFinderRef rf)\n        {\n            if (rf.isSceneRef)\n            {\n                Add(rf.component);\n            } else\n            {\n                Add(rf.asset.guid);\n            }\n        }\n\n        public void Remove(AssetFinderRef rf)\n        {\n            if (rf.isSceneRef)\n            {\n                Remove(rf.component);\n            } else\n            {\n                Remove(rf.asset.guid);\n            }\n        }\n\n        public void SetDirty()\n        {\n            drawer.SetDirty();\n        }\n\n        public event Action OnSelectionChanged;\n\n        public void SyncFromGlobalSelection()\n        {\n            var manager = AssetFinderSelectionManager.Instance;\n            \n            Clear();\n            \n            // Copy from global selection to local selection\n            if (manager.IsSelectingSceneObjects)\n            {\n                foreach (var go in manager.SceneSelection.GameObjects)\n                {\n                    if (go != null) Add(go);\n                }\n            }\n            else if (manager.IsSelectingAssets)\n            {\n                foreach (var entry in manager.AssetSelection.AssetEntries)\n                {\n                    Add(entry.guid);\n                }\n            }\n            \n            dirty = true;\n        }\n\n        public UnityObject[] GetUnityObjects()\n        {\n            var result = new System.Collections.Generic.List<UnityObject>();\n            \n            // Add scene objects from local selection\n            foreach (string instIdStr in instSet)\n            {\n                if (int.TryParse(instIdStr, out int instId))\n                {\n                    var obj = EditorUtility.InstanceIDToObject(instId);\n                    if (obj != null) result.Add(obj);\n                }\n            }\n            \n            // Add asset objects from local selection\n            foreach (string guid in guidSet)\n            {\n                string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n                if (!string.IsNullOrEmpty(assetPath))\n                {\n                    var obj = AssetDatabase.LoadAssetAtPath<UnityObject>(assetPath);\n                    if (obj != null) result.Add(obj);\n                }\n            }\n            \n            return result.ToArray();\n        }\n\n        public void SetUnityObjects(UnityObject[] objects)\n        {\n            Clear();\n            \n            if (objects != null)\n            {\n                foreach (var obj in objects)\n                {\n                    if (obj == null) continue;\n                    \n                    if (obj.IsSceneObject())\n                    {\n                        Add(obj);\n                    }\n                    else\n                    {\n                        string assetPath = AssetDatabase.GetAssetPath(obj);\n                        if (!string.IsNullOrEmpty(assetPath))\n                        {\n                            string guid = AssetDatabase.AssetPathToGUID(assetPath);\n                            if (!string.IsNullOrEmpty(guid))\n                            {\n                                Add(guid);\n                            }\n                        }\n                    }\n                }\n            }\n            \n            dirty = true;\n            // Trigger refresh after manually setting selection\n            OnSelectionChanged?.Invoke();\n        }\n        public void RefreshView()\n        {\n            if (refs == null) refs = new Dictionary<string, AssetFinderRef>();\n            refs.Clear();\n\n            if (instSet.Count > 0)\n            {\n                foreach (string instId in instSet)\n                {\n                    refs.Add(instId, new AssetFinderSceneRef(0, EditorUtility.InstanceIDToObject(int.Parse(instId))));\n                }\n            } else\n            {\n                foreach (string guid in guidSet)\n                {\n                    AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                    refs.Add(guid, new AssetFinderRef(0, 0, asset, null)\n                    {\n                        isSceneRef = false\n                    });\n                }\n            }\n\n            drawer.SetRefs(refs);\n            dirty = false;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/AssetFinderSelection.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f060e78650ad24e4d9f1d569a68bd676\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenRendererInformation.cs",
    "content": "using System;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct EnlightenRendererInformation\n        {\n            public Object renderer;\n            public Vector4 dynamicLightmapSTInSystem;\n            public int systemId;\n            public Hash128 instanceHash;\n            public Hash128 geometryHash;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenRendererInformation.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4882851dfb7a7034587c4d1089108d9a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSceneMapping.cs",
    "content": "using System;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private sealed class EnlightenSceneMapping\n        {\n            [SerializeField] private EnlightenRendererInformation[] m_Renderers;\n\n            [SerializeField] private EnlightenSystemInformation[] m_Systems;\n\n            [SerializeField] private Hash128[] m_Probesets;\n\n            [SerializeField] private EnlightenSystemAtlasInformation[] m_SystemAtlases;\n\n            [SerializeField] private EnlightenTerrainChunksInformation[] m_TerrainChunks;\n\n            public EnlightenRendererInformation[] renderers\n            {\n                get => m_Renderers;\n                set => m_Renderers = value;\n            }\n\n            public EnlightenSystemInformation[] systems\n            {\n                get => m_Systems;\n                set => m_Systems = value;\n            }\n\n            public Hash128[] probesets\n            {\n                get => m_Probesets;\n                set => m_Probesets = value;\n            }\n\n            public EnlightenSystemAtlasInformation[] systemAtlases\n            {\n                get => m_SystemAtlases;\n                set => m_SystemAtlases = value;\n            }\n\n            public EnlightenTerrainChunksInformation[] terrainChunks\n            {\n                get => m_TerrainChunks;\n                set => m_TerrainChunks = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSceneMapping.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 53fb54741d26bda46aebb9440e0636ae\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemAtlasInformation.cs",
    "content": "using System;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct EnlightenSystemAtlasInformation\n        {\n            public int atlasSize;\n            public Hash128 atlasHash;\n            public int firstSystemId;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemAtlasInformation.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5083c33ffcca383488fda513a64e8794\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemInformation.cs",
    "content": "using System;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct EnlightenSystemInformation\n        {\n            public int rendererIndex;\n            public int rendererSize;\n            public int atlasIndex;\n            public int atlasOffsetX;\n            public int atlasOffsetY;\n            public Hash128 inputSystemHash;\n            public Hash128 radiositySystemHash;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenSystemInformation.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fb6bd2f4c5d7a0a4182b2a45867d2c7a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenTerrainChunksInformation.cs",
    "content": "using System;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct EnlightenTerrainChunksInformation\n        {\n            public int firstSystemId;\n            public int numChunksInX;\n            public int numChunksInY;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.EnlightenTerrainChunksInformation.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ce351963a678fcd4c88cef2fd06e353b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightBakingOutput.cs",
    "content": "using System;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct LightBakingOutput\n        {\n            public int serializedVersion;\n            public int probeOcclusionLightIndex;\n            public int occlusionMaskChannel;\n            public LightmapBakeMode lightmapBakeMode;\n            public bool isBaked;\n\n            [Serializable]\n            public struct LightmapBakeMode\n            {\n                public LightmapBakeType lightmapBakeType;\n                public MixedLightingMode mixedLightingMode;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightBakingOutput.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2510794c594290744aecc37a3c152570\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightingDataAssetRoot.cs",
    "content": "using System;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Rendering;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private sealed class LightingDataAssetRoot\n        {\n            public SerializedData LightingDataAsset;\n\n            [Serializable]\n            public struct SerializedData\n            {\n                public int serializedVersion;\n                public SceneAsset m_Scene;\n                public LightmapData[] m_Lightmaps;\n                public Texture2D[] m_AOTextures;\n                public string[] m_LightmapsCacheFiles;\n                public LightProbes m_LightProbes;\n                public int m_LightmapsMode;\n                public SphericalHarmonicsL2 m_BakedAmbientProbeInLinear;\n                public RendererData[] m_LightmappedRendererData;\n                public SceneObjectIdentifier[] m_LightmappedRendererDataIDs;\n                public EnlightenSceneMapping m_EnlightenSceneMapping;\n                public SceneObjectIdentifier[] m_EnlightenSceneMappingRendererIDs;\n                public SceneObjectIdentifier[] m_Lights;\n                public LightBakingOutput[] m_LightBakingOutputs;\n                public string[] m_BakedReflectionProbeCubemapCacheFiles;\n                public Texture[] m_BakedReflectionProbeCubemaps;\n                public SceneObjectIdentifier[] m_BakedReflectionProbes;\n                public byte[] m_EnlightenData;\n                public int m_EnlightenDataVersion;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightingDataAssetRoot.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cd480560ce5931e4192adf9c234df09f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightmapData.cs",
    "content": "using System;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct LightmapData\n        {\n            [SerializeField] private Texture2D m_Lightmap;\n\n            [SerializeField] private Texture2D m_DirLightmap;\n\n            [SerializeField] private Texture2D m_ShadowMask;\n\n            public Texture2D lightmap\n            {\n                get => m_Lightmap;\n                set => m_Lightmap = value;\n            }\n\n            public Texture2D dirLightmap\n            {\n                get => m_DirLightmap;\n                set => m_DirLightmap = value;\n            }\n\n            public Texture2D shadowMask\n            {\n                get => m_ShadowMask;\n                set => m_ShadowMask = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.LightmapData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4199aa256da348d40b1ed01a2b54c60d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.RendererData.cs",
    "content": "using System;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct RendererData\n        {\n            public Mesh uvMesh;\n            public Vector4 terrainDynamicUVST;\n            public Vector4 terrainChunkDynamicUVST;\n            public Vector4 lightmapST;\n            public Vector4 lightmapSTDynamic;\n            public ushort lightmapIndex;\n            public ushort lightmapIndexDynamic;\n            public Hash128 explicitProbeSetHash;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.RendererData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0117d519295b4fa4da351c0103d00cdb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.SceneObjectIdentifier.cs",
    "content": "using System;\nusing UnityEditor;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        [Serializable]\n        private struct SceneObjectIdentifier : IEquatable<SceneObjectIdentifier>\n        {\n            public long targetObject;\n\n            public long targetPrefab;\n\n            public SceneObjectIdentifier(GlobalObjectId id)\n            {\n                if (id.identifierType != 2) throw new ArgumentException(\"GlobalObjectId must refer to a scene object.\", nameof(id));\n\n                targetObject = unchecked((long)id.targetObjectId);\n                targetPrefab = unchecked((long)id.targetPrefabId);\n            }\n\n            public bool Equals(SceneObjectIdentifier other)\n            {\n                return (targetObject == other.targetObject) && (targetPrefab == other.targetPrefab);\n            }\n\n            // public GlobalObjectId ToGlobalObjectId(SceneAsset scene)\n            // {\n            //     return ToGlobalObjectId(AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(scene)));\n            // }\n            //\n            // public GlobalObjectId ToGlobalObjectId(Scene scene)\n            // {\n            //     return ToGlobalObjectId(AssetDatabase.GUIDFromAssetPath(scene.path));\n            // }\n            //\n            // public GlobalObjectId ToGlobalObjectId(GUID sceneGuid)\n            // {\n            //     GlobalObjectId id;\n            //     GlobalObjectId.TryParse($\"GlobalObjectId_V1-2-{sceneGuid}-{unchecked((ulong)targetObject)}-{unchecked((ulong)targetPrefab)}\", out id);\n            //     return id;\n            // }\n            //\n            // public static Object SceneObjectIdentifierToObjectSlow(SceneAsset scene, SceneObjectIdentifier id)\n            // {\n            //     return SceneObjectIdentifierToObjectSlow(AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(scene)), id);\n            // }\n            //\n            // public static Object SceneObjectIdentifierToObjectSlow(Scene scene, SceneObjectIdentifier id)\n            // {\n            //     return SceneObjectIdentifierToObjectSlow(AssetDatabase.GUIDFromAssetPath(scene.path), id);\n            // }\n            //\n            // public static Object SceneObjectIdentifierToObjectSlow(GUID sceneGuid, SceneObjectIdentifier id)\n            // {\n            //     return GlobalObjectId.GlobalObjectIdentifierToObjectSlow(id.ToGlobalObjectId(sceneGuid));\n            // }\n            //\n            // public static void SceneObjectIdentifiersToObjectsSlow(SceneAsset scene, SceneObjectIdentifier[] identifiers, Object[] outputObjects)\n            // {\n            //     SceneObjectIdentifiersToObjectsSlow(AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(scene)), identifiers, outputObjects);\n            // }\n            //\n            // public static void SceneObjectIdentifiersToObjectsSlow(Scene scene, SceneObjectIdentifier[] identifiers, Object[] outputObjects)\n            // {\n            //     SceneObjectIdentifiersToObjectsSlow(AssetDatabase.GUIDFromAssetPath(scene.path), identifiers, outputObjects);\n            // }\n\n            // public static void SceneObjectIdentifiersToObjectsSlow(GUID sceneGuid, SceneObjectIdentifier[] identifiers, Object[] outputObjects)\n            // {\n            //     var globalIdentifiers = new GlobalObjectId[identifiers.Length];\n            //\n            //     for (int i = 0; i < identifiers.Length; i++)\n            //         globalIdentifiers[i] = identifiers[i].ToGlobalObjectId(sceneGuid);\n            //\n            //     GlobalObjectId.GlobalObjectIdentifiersToObjectsSlow(globalIdentifiers, outputObjects);\n            // }\n            //\n            // public static void GetSceneObjectIdentifiersSlow(Object[] objects, SceneObjectIdentifier[] outputIdentifiers)\n            // {\n            //     var globalIdentifiers = new GlobalObjectId[outputIdentifiers.Length];\n            //     GlobalObjectId.GetGlobalObjectIdsSlow(objects, globalIdentifiers);\n            //\n            //     for (int i = 0; i < outputIdentifiers.Length; i++)\n            //     {\n            //         outputIdentifiers[i] = new SceneObjectIdentifier(globalIdentifiers[i]);\n            //     }\n            // }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.SceneObjectIdentifier.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3b7c7436785d2c04aac3b9aefa0aba9e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.cs",
    "content": "// CREDITS:\n// https://github.com/NewBloodInteractive/com.newblood.lighting-internals/tree/master\n//\n\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderLightmap\n    {\n        public static IEnumerable<Texture> Read(LightingDataAsset source)\n        {\n            string json = EditorJsonUtility.ToJson(source);\n            var result = new LightingDataAssetRoot();\n            EditorJsonUtility.FromJsonOverwrite(json, result);\n\n            foreach (LightmapData item in result.LightingDataAsset.m_Lightmaps)\n            {\n                if (item.lightmap != null) yield return item.lightmap;\n                if (item.dirLightmap != null) yield return item.dirLightmap;\n                if (item.shadowMask != null) yield return item.shadowMask;\n            }\n\n            foreach (Texture2D item in result.LightingDataAsset.m_AOTextures)\n            {\n                if (item != null) yield return item;\n            }\n\n            foreach (Texture item in result.LightingDataAsset.m_BakedReflectionProbeCubemaps)\n            {\n                if (item != null) yield return item;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap/AssetFinderLightmap.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4ef2874116395ab4fac519172fee4b55\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules/Lightmap.meta",
    "content": "fileFormatVersion: 2\nguid: c696eb171b5a447892765b00918930bf\ntimeCreated: 1746366352"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Modules.meta",
    "content": "fileFormatVersion: 2\nguid: f93164c19bf346c0b7e1c7ed69192524\ntimeCreated: 1746366271"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Monitor/AssetFinderCacheHelper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [InitializeOnLoad]\n    internal class AssetFinderCacheHelper : AssetPostprocessor\n    {\n        [NonSerialized] private static HashSet<string> scenes;\n        [NonSerialized] private static HashSet<string> guidsIgnore;\n        [NonSerialized] internal static bool inited = false;\n        \n        static AssetFinderCacheHelper()\n        {\n            try\n            {\n                EditorApplication.update -= InitHelper;\n                EditorApplication.update += InitHelper;\n            }\n            catch (Exception e)\n            {\n                AssetFinderLOG.LogWarning(e);\n            }\n        }\n\n        private static void OnPostprocessAllAssets(\n            string[] importedAssets, string[] deletedAssets,\n            string[] movedAssets,\n            string[] movedFromAssetPaths)\n        {\n\n            if (AssetFinderSettingExt.disable) return;\n            if (EditorApplication.isPlayingOrWillChangePlaymode) return;\n            if (!AssetFinderSettingExt.isAutoRefreshEnabled) return; // OFF mode: do nothing\n\n            //Debug.Log(\"OnPostProcessAllAssets : \" + \":\" + importedAssets.Length + \":\" + deletedAssets.Length + \":\" + movedAssets.Length + \":\" + movedFromAssetPaths.Length);\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.Log($\"Not ready, will refresh anyway {importedAssets.Length} !\\n{string.Join(\"\\n\", importedAssets)}\");\n                return;\n            }\n\n            // FR2 not yet ready\n            if (AssetFinderCache.Api.AssetMap == null) return;\n            AssetFinderCache.DelayCheck4Changes();\n\n            // Handle new/changed assets based on current processing state\n            bool shouldInterruptUsedByBuild = false;\n            \n            for (var i = 0; i < importedAssets.Length; i++)\n            {\n                if (importedAssets[i] == AssetFinderCache.CachePath) continue;\n\n                string guid = AssetDatabase.AssetPathToGUID(importedAssets[i]);\n                if (!AssetFinderAsset.IsValidGUID(guid)) continue;\n\n                if (AssetFinderCache.Api.AssetMap.ContainsKey(guid))\n                {\n                    // Get the asset to check if it's critical\n                    var asset = AssetFinderCache.Api.Get(guid);\n                    if (asset != null && !asset.IsCriticalAsset())\n                    {\n                        // Skip marking non-critical assets as dirty\n                        AssetFinderLOG.Log($\"Skipping non-critical asset change: {importedAssets[i]}\");\n                        continue;\n                    }\n                    \n                    // Asset already exists - mark as dirty for re-processing\n                    AssetFinderCache.Api.RefreshAsset(guid, true);\n                    \n                    AssetFinderLOG.Log(\"Changed : \" + importedAssets[i]);\n                    // If we're building usedBy map, we need to interrupt and restart from content reading\n                    if (AssetFinderCache.Api.currentState == ProcessingState.BuildingUsedBy)\n                    {\n                        shouldInterruptUsedByBuild = true;\n                    }\n                    continue;\n                }\n\n                // New asset - add to AssetMap and queue for processing\n                AssetFinderCache.Api.AddAsset(guid);\n                AssetFinderLOG.Log(\"New : \" + importedAssets[i]);\n\n                // If we're building usedBy map, we need to interrupt and restart from content reading\n                if (AssetFinderCache.Api.currentState == ProcessingState.BuildingUsedBy)\n                {\n                    shouldInterruptUsedByBuild = true;\n                }\n            }\n\n            for (var i = 0; i < deletedAssets.Length; i++)\n            {\n                string guid = AssetDatabase.AssetPathToGUID(deletedAssets[i]);\n                if (AssetFinderSettingExt.isAutoRefreshEnabled)\n                {\n                    AssetFinderCache.Api.RemoveAsset(guid);\n                }\n                AssetFinderLOG.Log(\"Deleted : \" + deletedAssets[i]);\n            }\n\n            for (var i = 0; i < movedAssets.Length; i++)\n            {\n                string guid = AssetDatabase.AssetPathToGUID(movedAssets[i]);\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                if (asset != null && asset.IsCriticalAsset()) \n                {\n                    // Only mark critical assets as dirty when moved\n                    asset.MarkAsDirty();\n                }\n            }\n\n            // Handle interruption if we were building usedBy and new assets were added\n            if (AssetFinderSettingExt.isAutoRefreshEnabled && shouldInterruptUsedByBuild)\n            {\n                AssetFinderLOG.Log(\"FR2: Interrupting usedBy build due to new assets, restarting from content reading\");\n                // Reset state to allow restart from content reading phase\n                AssetFinderCache.Api.currentState = ProcessingState.Idle;\n                \n                // Force a complete refresh to restart from content reading\n                AssetFinderCache.Api.IncrementalRefresh();\n                return;\n            }\n\n            if (AssetFinderSettingExt.isAutoRefreshEnabled)\n            {\n                AssetFinderLOG.Log(\"Changes :: \" + importedAssets.Length + \"/\" + AssetFinderCache.Api.workCount);\n                AssetFinderCache.Api.Check4Work();\n            }\n        }\n        \n        internal static void InitHelper()\n        {\n            if (AssetFinderUnity.isEditorCompiling || AssetFinderUnity.isEditorUpdating) return;\n            if (!AssetFinderCache.isReady) return;\n            EditorApplication.update -= InitHelper;\n            \n            inited = true;\n            InitListScene();\n            InitIgnore();\n            CheckGitStatus(false);\n            \n#if UNITY_2018_1_OR_NEWER\n            EditorBuildSettings.sceneListChanged -= InitListScene;\n            EditorBuildSettings.sceneListChanged += InitListScene;\n#endif\n\n            #if UNITY_2022_1_OR_NEWER\n            EditorApplication.projectWindowItemInstanceOnGUI -= OnGUIProjectInstance;\n            EditorApplication.projectWindowItemInstanceOnGUI += OnGUIProjectInstance;\n            #else\n            EditorApplication.projectWindowItemOnGUI -= OnGUIProjectItem;\n            EditorApplication.projectWindowItemOnGUI += OnGUIProjectItem;\n            #endif\n\n            InitIgnore();\n            // force repaint all project panels\n            EditorApplication.RepaintProjectWindow();\n        }\n        \n        private static void CheckGitStatus(bool force)\n        {\n            if (AssetFinderSettingExt.gitIgnoreAdded && !force) return;\n            AssetFinderSettingExt.isGitProject = AssetFinderGitUtil.IsGitProject();\n            if (!AssetFinderSettingExt.isGitProject) return;\n            AssetFinderSettingExt.gitIgnoreAdded = AssetFinderGitUtil.CheckGitIgnoreContainsFR2Cache();\n        }\n        \n        public static void InitIgnore()\n        {\n            guidsIgnore = new HashSet<string>();\n            foreach (string item in AssetFinderSetting.IgnoreAsset)\n            {\n                string guid = AssetDatabase.AssetPathToGUID(item);\n                guidsIgnore.Add(guid);\n            }\n            \n            // Debug.Log($\"Init Ignore: {guidsIgnore.Count} items\");\n        }\n\n        private static void InitListScene()\n        {\n            scenes = new HashSet<string>();\n\n            // string[] scenes = new string[sceneCount];\n            foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)\n            {\n                string sce = AssetDatabase.AssetPathToGUID(scene.path);\n                scenes.Add(sce);\n            }\n        }\n\n        private static string lastGUID;\n        private static readonly Dictionary<int, GUIContent> _countContentCache = new Dictionary<int, GUIContent>();\n        private static GUIContent _plusContent;\n\n        private static void OnGUIProjectInstance(int instanceID, Rect selectionRect)\n        {\n            if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(instanceID, out string guid, out long localId)) return;\n\n            bool isMainAsset = guid != lastGUID;\n            lastGUID = guid;\n\n            if (isMainAsset)\n            {\n                DrawProjectItem(guid, selectionRect);\n                return;\n            }\n            \n            if (!AssetFinderCache.Api.setting.showSubAssetFileId) return;\n            var rect2 = selectionRect;\n            \n            // Cache the localId GUIContent to avoid repeated creation\n            if (!_countContentCache.TryGetValue((int)localId, out GUIContent label))\n            {\n                label = new GUIContent(localId.ToString());\n                _countContentCache[(int)localId] = label;\n            }\n            \n            rect2.xMin = rect2.xMax - EditorStyles.miniLabel.CalcSize(label).x;\n\n            var c = GUI.color;\n            GUI.color = new Color(.5f, .5f, .5f, 0.5f);\n            GUI.Label(rect2, label, EditorStyles.miniLabel);\n            GUI.color = c;\n        }\n\n        private static void OnGUIProjectItem(string guid, Rect rect)\n        {\n            bool isMainAsset = guid != lastGUID;\n            lastGUID = guid;\n            if (isMainAsset) DrawProjectItem(guid, rect);\n        }\n\n        private static void DrawProjectItem(string guid, Rect rect)\n        {\n            var r = new Rect(rect.x, rect.y, 1f, 16f);\n            if (scenes.Contains(guid))\n                EditorGUI.DrawRect(r, GUI2.Theme(new Color32(72, 150, 191, 255), Color.blue));\n            else if (guidsIgnore.Contains(guid))\n            {\n                var ignoreRect = new Rect(rect.x + 3f, rect.y + 6f, 2f, 2f);\n                EditorGUI.DrawRect(ignoreRect, GUI2.darkRed);\n            }\n\n            if (!AssetFinderCache.isReady) return; // not ready\n            if (!AssetFinderSetting.ShowReferenceCount) return;\n\n            AssetFinderCache api = AssetFinderCache.Api;\n            if (AssetFinderCache.Api.AssetMap == null) AssetFinderCache.Api.Check4Changes(false);\n            if (!api.AssetMap.TryGetValue(guid, out AssetFinderAsset item)) return;\n\n            if (item == null || item.UsedByMap == null) return;\n\n            if (item.UsedByMap.Count > 0)\n            {\n                // Cache GUIContent to avoid allocation\n                int count = item.UsedByMap.Count;\n                if (!_countContentCache.TryGetValue(count, out GUIContent content))\n                {\n                    content = AssetFinderGUIContent.FromString(count.ToString());\n                    _countContentCache[count] = content;\n                }\n                \n                r.width = 0f;\n                r.xMin -= 100f;\n                GUI.Label(r, content, GUI2.miniLabelAlignRight);\n            } else if (item.forcedIncludedInBuild)\n            {\n                var c = GUI.color;\n                GUI.color = c.Alpha(0.2f);\n                \n                // Cache plus content\n                if (_plusContent == null)\n                    _plusContent = AssetFinderGUIContent.FromString(\"+\");\n                \n                r.width = 0f;\n                r.xMin -= 100f;\n                GUI.Label(r, _plusContent, GUI2.miniLabelAlignRight);\n                GUI.color = c;\n            }\n            \n            // CRITICAL FIX: Show warning indicator when auto refresh is off and cache might be stale\n            // Only show for assets that might have reference count issues\n            if (!AssetFinderSettingExt.isAutoRefreshEnabled && api.workCount > 0)\n            {\n                var warningRect = new Rect(rect.xMax - 8f, rect.y + 1f, 6f, 6f);\n                Color oldColor = GUI.color;\n                GUI.color = Color.yellow;\n                EditorGUI.DrawRect(warningRect, Color.yellow);\n                GUI.color = oldColor;\n                \n                // Tooltip to explain the warning\n                if (warningRect.Contains(Event.current.mousePosition))\n                {\n                    GUI.Label(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 200f, 40f), \n                             new GUIContent(\"Auto refresh is disabled. Reference counts may be outdated. Use Window > Find Reference 2 to force refresh.\"));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Monitor/AssetFinderCacheHelper.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 64bfab0751586794ca327787084e5533\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Monitor.meta",
    "content": "fileFormatVersion: 2\nguid: 07b0445a569d44558e573b4457f34c6b\ntimeCreated: 1746366842"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRef.cs",
    "content": "using System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n    internal class AssetFinderRef\n    {\n\n        public AssetFinderAsset addBy;\n        \n        // Callback delegates for advanced bookmark operations (set by the drawer)\n        public System.Action<AssetFinderRef> OnCtrlClick;\n        public System.Action<AssetFinderRef> OnAltClick;\n        public System.Action<AssetFinderRef> OnShiftClick;\n        public AssetFinderAsset asset;\n        public Object component;\n        public int depth;\n        public string group;\n        public int index;\n\n        public bool isSceneRef;\n        public int matchingScore;\n        public int type;\n\n        public AssetFinderRef()\n        { }\n\n        public AssetFinderRef(int index, int depth, AssetFinderAsset asset, AssetFinderAsset by)\n        {\n            this.index = index;\n            this.depth = depth;\n\n            this.asset = asset;\n            if (asset != null) type = AssetFinderAssetGroupDrawer.GetIndex(asset.extension);\n\n            addBy = by;\n\n            // isSceneRef = false;\n        }\n\n        public AssetFinderRef(int index, int depth, AssetFinderAsset asset, AssetFinderAsset by, string group) : this(index, depth, asset,\n            by)\n        {\n            this.group = group;\n\n            // isSceneRef = false;\n        }\n        private static int CSVSorter(AssetFinderRef item1, AssetFinderRef item2)\n        {\n            int r = item1.depth.CompareTo(item2.depth);\n            if (r != 0) return r;\n\n            int t = item1.type.CompareTo(item2.type);\n            if (t != 0) return t;\n\n            return item1.index.CompareTo(item2.index);\n        }\n\n\n        public static AssetFinderRef[] FromDict(Dictionary<string, AssetFinderRef> dict)\n        {\n            if (dict == null || dict.Count == 0) return null;\n\n            var result = new List<AssetFinderRef>();\n\n            foreach (KeyValuePair<string, AssetFinderRef> kvp in dict)\n            {\n                if (kvp.Value == null) continue;\n                if (kvp.Value.asset == null) continue;\n\n                result.Add(kvp.Value);\n            }\n\n            result.Sort(CSVSorter);\n\n\n            return result.ToArray();\n        }\n\n        public static AssetFinderRef[] FromList(List<AssetFinderRef> list)\n        {\n            if (list == null || list.Count == 0) return null;\n\n            list.Sort(CSVSorter);\n            var result = new List<AssetFinderRef>();\n            for (var i = 0; i < list.Count; i++)\n            {\n                if (list[i].asset == null) continue;\n                result.Add(list[i]);\n            }\n            return result.ToArray();\n        }\n\n        public override string ToString()\n        {\n            if (isSceneRef)\n            {\n                var sr = (AssetFinderSceneRef)this;\n                return sr.scenePath;\n            }\n\n            return asset.assetPath;\n        }\n\n        public string GetSceneObjId()\n        {\n            if (component == null) return string.Empty;\n\n            return component.GetInstanceID().ToString();\n        }\n\n        public virtual bool isSelected()\n        {\n            return AssetFinderBookmark.Contains(asset.guid);\n        }\n        public virtual void DrawToogleSelect(Rect r)\n        {\n            bool s = isSelected();\n            r.width = 16f;\n            \n            Event evt = Event.current;\n            bool isMouseOver = r.Contains(evt.mousePosition);\n            bool isMouseDown = evt.type == EventType.MouseDown && evt.button == 0 && isMouseOver;\n            \n            // Handle modifier keys for advanced selection\n            if (isMouseDown)\n            {\n                bool ctrl = Application.platform == RuntimePlatform.OSXEditor ? evt.command : evt.control;\n                bool alt = evt.alt;\n                bool shift = evt.shift;\n                \n                if (shift)\n                {\n                    // Shift+click: Toggle all items in all groups\n                    OnShiftClick?.Invoke(this);\n                    evt.Use();\n                    return;\n                }\n                else if (alt)\n                {\n                    // Alt+click: Toggle all siblings in the same group\n                    OnAltClick?.Invoke(this);\n                    evt.Use();\n                    return;\n                }\n                else if (ctrl)\n                {\n                    // Cmd+click (Mac) / Ctrl+click (PC): Toggle self and set all siblings to the same new state\n                    OnCtrlClick?.Invoke(this);\n                    evt.Use();\n                    return;\n                }\n            }\n            \n            // Normal toggle behavior\n            if (!GUI2.Toggle(r, ref s)) return;\n\n            if (s)\n            {\n                AssetFinderBookmark.Add(this);\n            } else\n            {\n                AssetFinderBookmark.Remove(this);\n            }\n        }\n\n        // Removed - now handled via instance callbacks\n        \n        // Removed - now handled via instance callbacks\n        \n        // Removed - now handled via instance callbacks\n        \n        // Removed - now handled via instance callbacks\n        \n\n\n        // public AssetFinderRef(int depth, UnityEngine.Object target)\n        // {\n        // \tthis.component = target;\n        // \tthis.depth = depth;\n        // \t// isSceneRef = true;\n        // }\n        internal List<AssetFinderRef> Append(Dictionary<string, AssetFinderRef> dict, params string[] guidList)\n        {\n            var result = new List<AssetFinderRef>();\n            if (!AssetFinderCache.isReady)\n            {\n                AssetFinderLOG.LogWarning(\"Cache not yet ready! Please wait!\");\n                return result;\n            }\n\n            // var excludePackage = !AssetFinderCache.Api.setting.showPackageAsset;\n            //filter to remove items that already in dictionary\n            for (var i = 0; i < guidList.Length; i++)\n            {\n                string guid = guidList[i];\n                if (dict.ContainsKey(guid)) continue;\n\n                AssetFinderAsset child = AssetFinderCache.Api.Get(guid);\n                if (child == null) continue;\n                // if (excludePackage && child.inPackages) continue;\n\n                var r = new AssetFinderRef(dict.Count, depth + 1, child, asset);\n                dict.Add(guid, r);\n                result.Add(r);\n            }\n\n            return result;\n        }\n\n        internal void AppendUsedBy(Dictionary<string, AssetFinderRef> result, bool deep)\n        {\n            // var list = Append(result, AssetFinderAsset.FindUsedByGUIDs(asset).ToArray());\n            // if (!deep) return;\n\n            // // Add next-level\n            // for (var i = 0;i < list.Count;i ++)\n            // {\n            // \tlist[i].AppendUsedBy(result, true);\n            // }\n\n            Dictionary<string, AssetFinderAsset> h = asset.UsedByMap;\n            List<AssetFinderRef> list = deep ? new List<AssetFinderRef>() : null;\n\n            if (asset.UsedByMap == null) return;\n            // bool excludePackage = !AssetFinderCache.Api.setting.showPackageAsset;\n\n            foreach (KeyValuePair<string, AssetFinderAsset> kvp in h)\n            {\n                string guid = kvp.Key;\n                if (result.ContainsKey(guid)) continue;\n\n                AssetFinderAsset child = AssetFinderCache.Api.Get(guid);\n                if (child == null) continue;\n                if (child.IsMissing) continue;\n                // if (excludePackage && child.inPackages) continue;\n\n                var r = new AssetFinderRef(result.Count, depth + 1, child, asset);\n                result.Add(guid, r);\n\n                if (deep) list.Add(r);\n            }\n\n            if (!deep) return;\n\n            foreach (AssetFinderRef item in list)\n            {\n                item.AppendUsedBy(result, true);\n            }\n        }\n\n        internal void AppendUsage(Dictionary<string, AssetFinderRef> result, bool deep)\n        {\n            Dictionary<string, HashSet<long>> h = asset.UseGUIDs;\n            List<AssetFinderRef> list = deep ? new List<AssetFinderRef>() : null;\n            // bool excludePackage = !AssetFinderCache.Api.setting.showPackageAsset;\n            foreach (KeyValuePair<string, HashSet<long>> kvp in h)\n            {\n                string guid = kvp.Key;\n                if (result.ContainsKey(guid)) continue;\n\n                AssetFinderAsset child = AssetFinderCache.Api.Get(guid);\n                if (child == null) continue;\n                if (child.IsMissing) continue;\n                // if (excludePackage && child.inPackages) continue;\n\n                var r = new AssetFinderRef(result.Count, depth + 1, child, asset);\n                result.Add(guid, r);\n\n                if (deep) list.Add(r);\n            }\n\n            if (!deep) return;\n\n            foreach (AssetFinderRef item in list)\n            {\n                item.AppendUsage(result, true);\n            }\n        }\n\n        // --------------------- STATIC UTILS -----------------------\n\n\n        internal static Dictionary<string, AssetFinderRef> FindRefs(string[] guids, bool usageOrUsedBy, bool addFolder)\n        {\n            var dict = new Dictionary<string, AssetFinderRef>();\n            var list = new List<AssetFinderRef>();\n            var selectedGuids = new HashSet<string>(guids);\n            // bool excludePackage = !AssetFinderCache.Api.setting.showPackageAsset;\n\n            for (var i = 0; i < guids.Length; i++)\n            {\n                string guid = guids[i];\n                if (dict.ContainsKey(guid)) continue;\n\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n                if (asset == null) continue;\n                // if (excludePackage && asset.inPackages) continue;\n\n                var r = new AssetFinderRef(i, 0, asset, null);\n                if (!asset.IsFolder || addFolder) dict.Add(guid, r);\n\n                list.Add(r);\n            }\n\n            for (var i = 0; i < list.Count; i++)\n            {\n                if (usageOrUsedBy)\n                {\n                    list[i].AppendUsage(dict, true);\n                } else\n                {\n                    list[i].AppendUsedBy(dict, true);\n                }\n            }\n\n            // Remove selected objects themselves from results (depth 0)\n            var filteredDict = new Dictionary<string, AssetFinderRef>();\n            foreach (KeyValuePair<string, AssetFinderRef> kvp in dict)\n            {\n                if (kvp.Value.depth == 0) continue; // Exclude selected objects\n                if (selectedGuids.Contains(kvp.Key)) continue; // Double-check exclusion\n                filteredDict.Add(kvp.Key, kvp.Value);\n            }\n\n            return filteredDict;\n        }\n\n\n        public static Dictionary<string, AssetFinderRef> FindUsage(string[] guids)\n        {\n            return FindRefs(guids, true, true);\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindUsedBy(string[] guids)\n        {\n            return FindRefs(guids, false, true);\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindUsageScene(GameObject[] objs, bool depth)\n        {\n            var dict = new Dictionary<string, AssetFinderRef>();\n\n            // var list = new List<AssetFinderRef>();\n\n            for (var i = 0; i < objs.Length; i++)\n            {\n                if (objs[i].IsAssetObject()) continue; //only get in scene \n\n                //add selection\n                if (!dict.ContainsKey(objs[i].GetInstanceID().ToString())) dict.Add(objs[i].GetInstanceID().ToString(), new AssetFinderSceneRef(0, objs[i]));\n\n                foreach (Object item in AssetFinderUnity.GetAllRefObjects(objs[i]))\n                {\n                    AppendUsageScene(dict, item);\n                }\n\n                if (!depth) continue;\n                foreach (GameObject child in AssetFinderUnity.getAllChild(objs[i]))\n                {\n                    foreach (Object item2 in AssetFinderUnity.GetAllRefObjects(child))\n                    {\n                        AppendUsageScene(dict, item2);\n                    }\n                }\n            }\n\n            return dict;\n        }\n\n        private static void AppendUsageScene(Dictionary<string, AssetFinderRef> dict, Object obj)\n        {\n            string path = AssetDatabase.GetAssetPath(obj);\n            if (string.IsNullOrEmpty(path)) return;\n\n            string guid = AssetDatabase.AssetPathToGUID(path);\n            if (string.IsNullOrEmpty(guid)) return;\n\n            if (dict.ContainsKey(guid)) return;\n\n            AssetFinderAsset asset = AssetFinderCache.Api.Get(guid);\n            if (asset == null) return;\n\n            // if (!AssetFinderCache.Api.setting.showPackageAsset && asset.inPackages) return;\n            var r = new AssetFinderRef(0, 1, asset, null);\n            dict.Add(guid, r);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRef.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 113e4d596d4ef334eb917e73db9d3bca\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Mode.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderRefDrawer\n    {\n        public enum Mode\n        {\n            Dependency,\n            Depth,\n            Type,\n            Extension,\n            Folder,\n            Atlas,\n            AssetBundle,\n            None\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Mode.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f9f137444bf56a849a40f847a7f4bfef\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Sort.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderRefDrawer\n    {\n        public enum Sort\n        {\n            Type,\n            Path,\n            Size\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.Sort.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 670354b3bb8b6ea4bb8aba114885a29b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderRefDrawer : IRefDraw\n    {\n        internal class RefDrawerConfig\n        {\n            public IWindow window;\n            public Func<Sort> getSortMode;\n            public Func<Mode> getGroupMode;\n            public bool showFullPath;\n            public bool showToggle = true;\n            public bool showHighlight = true;\n            public Func<bool> shouldShowExtension;\n            public Func<bool> shouldShowDetailButton;\n            public Action onCacheInvalidated;\n        }\n\n        internal class AssetDrawingConfig : RefDrawerConfig\n        {\n            public bool showFileSize;\n            public bool showExtension;\n            public bool showUsageType;\n            public bool showAssetBundleName;\n            public bool showAtlasName;\n        }\n\n        internal class SceneDrawingConfig : RefDrawerConfig\n        {\n            public bool showDetails;\n        }\n\n        public static GUIStyle toolbarSearchField;\n        public static GUIStyle toolbarSearchFieldCancelButton;\n        public static GUIStyle toolbarSearchFieldCancelButtonEmpty;\n        private readonly Dictionary<string, BookmarkInfo> gBookmarkCache = new Dictionary<string, BookmarkInfo>();\n        private readonly Func<Mode> getGroupMode;\n\n        private readonly Func<Sort> getSortMode;\n\n        internal readonly AssetFinderTreeUI2.GroupDrawer groupDrawer;\n\n        public readonly List<AssetFinderAsset> highlight = new List<AssetFinderAsset>();\n\n        // FILTERING\n        private readonly string searchTerm = string.Empty;\n        private readonly bool showSearch = true;\n        public Action<Rect, AssetFinderRef> afterItemDraw;\n        public Action<Rect, AssetFinderRef> beforeItemDraw;\n        public bool caseSensitive = false;\n\n        public Action<Rect, string, int> customDrawGroupLabel;\n\n        public Func<AssetFinderRef, string> customGetGroup;\n\n        // STATUS\n        private bool dirty;\n        public RefDrawerConfig Config { get; private set; }\n        private int excludeCount;\n        public AssetDrawingConfig AssetConfig { get; private set; }\n        public SceneDrawingConfig SceneConfig { get; private set; }\n\n        public string level0Group;\n        internal List<AssetFinderRef> list;\n        public string messageEmpty = \"It's empty!\";\n\n        public string messageNoRefs = \"Do select something!\";\n        internal Dictionary<string, AssetFinderRef> refs;\n        private bool selectFilter;\n        public bool showDetail;\n        private bool showIgnore;\n        public float paddingLeft = -4f;\n        public float paddingRight = 0f;\n        \n        // Track whether we have a valid selection (independent of refs count)\n        private bool hasValidSelection = false;\n        \n        // Hook for getting contextual empty message from external source (e.g. window)\n        public Func<string> GetContextualEmptyMessage;\n\n\n        public AssetFinderRefDrawer(RefDrawerConfig config)\n        {\n            this.window = config.window;\n            this.getSortMode = config.getSortMode;\n            this.getGroupMode = config.getGroupMode;\n            this.Config = config;\n            this.AssetConfig = config as AssetDrawingConfig ?? new AssetDrawingConfig();\n            this.SceneConfig = config as SceneDrawingConfig ?? new SceneDrawingConfig();\n            groupDrawer = new AssetFinderTreeUI2.GroupDrawer(DrawGroup, DrawAsset);\n        }\n\n\n\n        // ORIGINAL\n        internal AssetFinderRef[] source => AssetFinderRef.FromList(list);\n\n        public IWindow window { get; set; }\n        \n        public bool IsDirty => dirty;\n        public bool Draw(Rect rect)\n        {\n            if (refs == null || refs.Count == 0)\n            {\n                // Show appropriate message based on whether we have a valid selection\n                string message = hasValidSelection ? (GetContextualEmptyMessage?.Invoke() ?? messageEmpty) : messageNoRefs;\n                DrawEmpty(rect, message);\n                return false;\n            }\n\n            if (dirty || list == null) ApplyFilter();\n\n            rect.xMin += paddingLeft;\n            rect.xMax += paddingRight;\n\n            if (!groupDrawer.hasChildren)\n            {\n                DrawEmpty(rect, GetContextualEmptyMessage?.Invoke() ?? messageEmpty);\n            } else\n            {\n                groupDrawer.Draw(rect);\n            }\n            return false;\n        }\n\n        public bool DrawLayout()\n        {\n            if (refs == null || refs.Count == 0) \n            {\n                // Only return false if we have no valid selection, otherwise continue to show empty message\n                return !hasValidSelection;\n            }\n\n            if (dirty || list == null) ApplyFilter();\n\n            if (groupDrawer.tree != null)\n            {\n                groupDrawer.tree.itemPaddingLeft = paddingLeft;\n                groupDrawer.tree.itemPaddingRight = paddingRight;\n            }\n            groupDrawer.DrawLayout();\n            return false;\n        }\n\n        public int ElementCount()\n        {\n            if (refs == null) return 0;\n\n            return refs.Count;\n\n            // return refs.Where(x => x.Value.depth != 0).Count();\n        }\n\n        private void DrawEmpty(Rect rect, string text)\n        {\n            rect = GUI2.Padding(rect, 2f, 2f);\n            rect.height = 45f;\n\n            // Determine message type based on message content\n            MessageType messageType = MessageType.Info;\n            if (text.Contains(\"not scanned\") || text.Contains(\"content changed\") || text.Contains(\"refresh cache\"))\n            {\n                messageType = MessageType.Warning;\n            }\n\n            EditorGUI.HelpBox(rect, text, messageType);\n        }\n        public void SetRefs(Dictionary<string, AssetFinderRef> dictRefs)\n        {\n            ValidateRefs(dictRefs);\n            refs = dictRefs;\n            SetupRefCallbacks();\n            \n            // When setting refs directly, we consider this a valid selection\n            hasValidSelection = true;\n            dirty = true;\n        }\n        \n        private void SetupRefCallbacks()\n        {\n            // Setup callbacks for each ref to point to this drawer\n            if (refs != null)\n            {\n                foreach (var kvp in refs)\n                {\n                    var rf = kvp.Value;\n                    rf.OnCtrlClick = HandleRefCtrlClick;\n                    rf.OnAltClick = HandleRefAltClick;\n                    rf.OnShiftClick = HandleRefShiftClick;\n                }\n            }\n        }\n\n        void ValidateRefs(Dictionary<string, AssetFinderRef> dictRefs)\n        {\n            var sceneRef = 0;\n            var assetRef = 0;\n            foreach (var kvp in dictRefs)\n            {\n                if (kvp.Value.isSceneRef) sceneRef++;\n                if (!kvp.Value.isSceneRef) assetRef++;\n                if (sceneRef > 0 && assetRef > 0)\n                {\n                    AssetFinderLOG.LogWarning(\"Mixed content???\");\n                }\n            }\n        }\n\n        private void SetBookmarkGroup(string groupLabel, bool willbookmark)\n        {\n            string[] ids = groupDrawer.GetChildren(groupLabel);\n            if (ids == null) return; // Handle case where group doesn't exist in groupDict\n            \n            for (var i = 0; i < ids.Length; i++)\n            {\n                AssetFinderRef rf;\n                if (!refs.TryGetValue(ids[i], out rf)) continue;\n\n                if (willbookmark)\n                {\n                    AssetFinderBookmark.Add(rf);\n                } else\n                {\n                    AssetFinderBookmark.Remove(rf);\n                }\n            }\n\n            // Invalidate cache so group toggles reflect the correct state\n            InvalidateGroupCache();\n        }\n\n        private BookmarkInfo GetBMInfo(string groupLabel)\n        {\n            BookmarkInfo info = null;\n            if (!gBookmarkCache.TryGetValue(groupLabel, out info))\n            {\n                string[] ids = groupDrawer.GetChildren(groupLabel);\n\n                info = new BookmarkInfo();\n                if (ids != null)\n                {\n                    for (var i = 0; i < ids.Length; i++)\n                    {\n                        AssetFinderRef rf;\n                        if (!refs.TryGetValue(ids[i], out rf)) continue;\n                        info.total++;\n\n                        bool isBM = AssetFinderBookmark.Contains(rf);\n                        if (isBM) info.count++;\n                    }\n                }\n\n                gBookmarkCache.Add(groupLabel, info);\n            }\n\n            return info;\n        }\n\n        private void DrawToggleGroup(Rect r, string groupLabel)\n        {\n            BookmarkInfo info = GetBMInfo(groupLabel);\n            bool selectAll = info.count == info.total;\n            r.width = 16f;\n            if (GUI2.Toggle(r, ref selectAll)) SetBookmarkGroup(groupLabel, selectAll);\n\n            if (!selectAll && (info.count > 0))\n            {\n                //GUI.DrawTexture(r, EditorStyles.\n            }\n        }\n\n        private void DrawGroup(Rect r, string label, int childCount)\n        {\n            if (string.IsNullOrEmpty(label)) label = \"(none)\";\n            DrawToggleGroup(r, label);\n            r.xMin += 18f;\n\n            Mode groupMode = getGroupMode();\n            if (groupMode == Mode.Folder)\n            {\n                Texture tex = AssetDatabase.GetCachedIcon(\"Assets\");\n                GUI.DrawTexture(new Rect(r.x, r.y, 16f, 16f), tex);\n                r.xMin += 16f;\n            }\n\n            if (customDrawGroupLabel != null)\n            {\n                customDrawGroupLabel.Invoke(r, label, childCount);\n            } else\n            {\n                GUIContent lbContent = AssetFinderGUIContent.FromString(label);\n                GUI.Label(r, lbContent, EditorStyles.label);\n\n                Rect cRect = r;\n                cRect.x += EditorStyles.label.CalcSize(lbContent).x;\n                cRect.y += 1f;\n                GUI.Label(cRect, AssetFinderGUIContent.FromString($\"({childCount})\"), EditorStyles.miniLabel);\n            }\n\n            bool hasMouse = (Event.current.type == EventType.MouseUp) && r.Contains(Event.current.mousePosition);\n            if (hasMouse && (Event.current.button == 1))\n            {\n                var menu = new GenericMenu();\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Add Bookmark\"), false, () => { SetBookmarkGroup(label, true); });\n                menu.AddItem(AssetFinderGUIContent.FromString(\"Remove Bookmark\"), false, () =>\n                {\n                    SetBookmarkGroup(label, false);\n                });\n\n                menu.ShowAsContext();\n                Event.current.Use();\n            }\n        }\n\n        public void DrawDetails(Rect rect)\n        {\n            Rect r = rect;\n            r.xMin += 18f;\n            r.height = 18f;\n\n            for (var i = 0; i < highlight.Count; i++)\n            {\n                highlight[i].Draw(\n                    r,\n                    new AssetFinderAsset.AssetFinderAssetDrawConfig(\n                        false,\n                    false,\n                    false,\n                    false,\n                    false,\n                    false,\n                        window,\n                        false\n                    )\n                );\n                r.y += 18f;\n                r.xMin += 18f;\n            }\n        }\n\n        private void DrawAsset(Rect r, string guid)\n        {\n            if (!refs.TryGetValue(guid, out AssetFinderRef rf)) return;\n\n            if (rf.isSceneRef)\n            {\n                if (rf.component == null) return;\n                if (!(rf is AssetFinderSceneRef re)) return;\n                beforeItemDraw?.Invoke(r, rf);\n\n                if (Config.showToggle)\n                {\n                rf.DrawToogleSelect(r);\n                r.xMin += 32f;\n                }\n                re.Draw(r, getGroupMode(), SceneConfig.showDetails, Config.showFullPath);\n            } else\n            {\n                beforeItemDraw?.Invoke(r, rf);\n\n                // Draw content first so right-side buttons handle mouse events before the bookmark toggle\n                Rect contentRect = r;\n                if (Config.showToggle) contentRect.xMin += 32f;\n\n                bool isHighlight = Config.showHighlight && highlight.Contains(rf.asset);\n\n                // if (isHighlight)\n                // {\n                //     var hlRect = new Rect(-20, r.y, 15f, r.height);\n                //     GUI2.Rect(hlRect, GUI2.darkGreen);\n                // }\n\n                // Use configurable delegates for behavior\n                bool shouldShowExtension = Config.shouldShowExtension?.Invoke() ?? AssetConfig.showExtension;\n                bool shouldShowDetailBtn = Config.shouldShowDetailButton?.Invoke() ?? true;\n                Action onShowDetail = () => {\n                        showDetail = true;\n                        highlight.Clear();\n                        highlight.Add(rf.asset);\n\n                        AssetFinderAsset p = rf.addBy;\n                        var cnt = 0;\n                        while ((p != null) && refs.ContainsKey(p.guid))\n                        {\n                            highlight.Add(p);\n                            AssetFinderRef AssetFinderref = refs[p.guid];\n                            if (AssetFinderref != null) p = AssetFinderref.addBy;\n                            if (++cnt > 100)\n                            {\n                                AssetFinderLOG.LogWarning(\"Break on depth 1000????\");\n                                break;\n                            }\n                        }\n\n                        highlight.Sort((item1, item2) =>\n                        {\n                            int d1 = refs[item1.guid].depth;\n                            int d2 = refs[item2.guid].depth;\n                            return d1.CompareTo(d2);\n                        });\n                        Event.current.Use();\n                    };\n                \n                rf.asset.Draw(\n                    contentRect,\n                    new AssetFinderAsset.AssetFinderAssetDrawConfig(\n                        isHighlight,\n                        Config.showFullPath,\n                        AssetConfig.showFileSize,\n                        AssetConfig.showAssetBundleName && AssetFinderSetting.s.displayAssetBundleName,\n                        AssetConfig.showAtlasName && AssetFinderSetting.s.displayAtlasName,\n                        AssetConfig.showUsageType,\n                        window,\n                        shouldShowExtension,\n                        shouldShowDetailBtn ? onShowDetail : null\n                    )\n                );\n\n                if (Config.showToggle)\n                {\n                    rf.DrawToogleSelect(r);\n                }\n            }\n\n            afterItemDraw?.Invoke(r, rf);\n        }\n\n        private string GetGroup(AssetFinderRef rf)\n        {\n            if (customGetGroup != null) return customGetGroup(rf);\n\n            if (rf.depth == 0) return level0Group;\n\n            if (getGroupMode() == Mode.None) return \"(no group)\";\n\n            AssetFinderSceneRef sr = null;\n            if (rf.isSceneRef)\n            {\n                sr = rf as AssetFinderSceneRef;\n                if (sr == null) return null;\n            }\n\n            if (!rf.isSceneRef)\n            {\n                if (rf.asset.IsExcluded)\n                {\n                    return null; // \"(ignored)\"\n                }\n            }\n\n            switch (getGroupMode())\n            {\n            case Mode.Extension:\n                {\n                    // if (!rf.isSceneRef) Debug.Log($\"Extension: {rf.asset.assetPath} | {rf.asset.extension}\");\n                    return rf.isSceneRef ? sr.targetType\n                        : string.IsNullOrEmpty(rf.asset.extension) ? \"(no extension)\" : rf.asset.extension;\n                }\n            case Mode.Type:\n                {\n                    return rf.isSceneRef ? sr.targetType : AssetFinderAssetGroupDrawer.FILTERS[rf.type].name;\n                }\n\n            case Mode.Folder: return rf.isSceneRef ? sr.scenePath : rf.asset.assetFolder;\n\n            case Mode.Dependency:\n                {\n                    return rf.depth == 1 ? \"Direct Usage\" : \"Indirect Usage\";\n                }\n\n            case Mode.Depth:\n                {\n                    return \"Level \" + rf.depth;\n                }\n\n            case Mode.Atlas: return rf.isSceneRef ? \"(not in atlas)\" : string.IsNullOrEmpty(rf.asset.AtlasName) ? \"(not in atlas)\" : rf.asset.AtlasName;\n            case Mode.AssetBundle: return rf.isSceneRef ? \"(not in assetbundle)\" : string.IsNullOrEmpty(rf.asset.AssetBundleName) ? \"(not in assetbundle)\" : rf.asset.AssetBundleName;\n            }\n\n            return \"(others)\";\n        }\n\n        private void SortGroup(List<string> groups)\n        {\n            groups.Sort((item1, item2) =>\n            {\n                if (item1.Contains(\"(\")) return 1;\n                if (item2.Contains(\"(\")) return -1;\n\n                return string.Compare(item1, item2, StringComparison.Ordinal);\n            });\n        }\n\n        public AssetFinderRefDrawer Reset(string[] assetGUIDs, bool isUsage) //, bool isSceneRef\n        {\n            gBookmarkCache.Clear();\n            \n            // Set hasValidSelection based on whether we received valid asset GUIDs\n            hasValidSelection = assetGUIDs != null && assetGUIDs.Length > 0;\n            refs = isUsage ? AssetFinderRef.FindUsage(assetGUIDs) : AssetFinderRef.FindUsedBy(assetGUIDs);\n            SetupRefCallbacks();\n            \n            // ValidateRefs(dictRefs);\n            \n            dirty = true;\n            if (list != null) list.Clear();\n            return this;\n        }\n\n        public void Reset(Dictionary<string, AssetFinderRef> newRefs)\n        {\n            if (refs == null) refs = new Dictionary<string, AssetFinderRef>();\n            refs.Clear();\n            ValidateRefs(newRefs);\n            \n            foreach (KeyValuePair<string, AssetFinderRef> kvp in newRefs)\n            {\n                refs.Add(kvp.Key, kvp.Value);\n            }\n            SetupRefCallbacks();\n            \n            // When resetting with refs directly, we consider this a valid selection\n            hasValidSelection = true;\n            \n            dirty = true;\n            if (list != null) list.Clear();\n        }\n\n        public AssetFinderRefDrawer Reset(GameObject[] objs, bool findDept, bool findPrefabInAsset)\n        {\n            // Set hasValidSelection based on whether we received valid GameObjects\n            hasValidSelection = objs != null && objs.Length > 0;\n            refs = AssetFinderRef.FindUsageScene(objs, findDept)\n                .Where(item=> !item.Value.isSceneRef)\n                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);\n\n            var guidss = new List<string>();\n            Dictionary<GameObject, HashSet<string>> dependent = AssetFinderSceneCache.Api.prefabDependencies;\n            foreach (GameObject gameObject in objs)\n            {\n                if (!dependent.TryGetValue(gameObject, out HashSet<string> hash)) continue;\n                foreach (string guid in hash)\n                {\n                    guidss.Add(guid);\n                }\n            }\n\n            Dictionary<string, AssetFinderRef> usageRefs1 = AssetFinderRef.FindUsage(guidss.ToArray());\n            foreach (KeyValuePair<string, AssetFinderRef> kvp in usageRefs1)\n            {\n                if (refs.ContainsKey(kvp.Key)) continue;\n\n                if (guidss.Contains(kvp.Key)) kvp.Value.depth = 1;\n\n                refs.Add(kvp.Key, kvp.Value);\n            }\n\n\n            if (findPrefabInAsset)\n            {\n                var guids = new List<string>();\n                for (var i = 0; i < objs.Length; i++)\n                {\n                    string guid = AssetFinderUnity.GetPrefabParent(objs[i]);\n                    if (string.IsNullOrEmpty(guid)) continue;\n\n                    guids.Add(guid);\n                }\n\n                Dictionary<string, AssetFinderRef> usageRefs = AssetFinderRef.FindUsage(guids.ToArray());\n                foreach (KeyValuePair<string, AssetFinderRef> kvp in usageRefs)\n                {\n                    if (refs.ContainsKey(kvp.Key)) continue;\n\n                    if (guids.Contains(kvp.Key)) kvp.Value.depth = 1;\n\n                    refs.Add(kvp.Key, kvp.Value);\n                }\n            }\n\n            SetupRefCallbacks();\n            dirty = true;\n            if (list != null) list.Clear();\n\n            return this;\n        }\n\n        //ref in scene\n        public AssetFinderRefDrawer Reset(string[] assetGUIDs)\n        {\n            // Set hasValidSelection based on whether we received valid asset GUIDs\n            hasValidSelection = assetGUIDs != null && assetGUIDs.Length > 0;\n            \n            refs = AssetFinderSceneRef.FindRefInScene(assetGUIDs, true, SetRefInScene);\n            SetupRefCallbacks();\n            dirty = true;\n            if (list != null) list.Clear();\n\n            return this;\n        }\n\n        private void SetRefInScene(Dictionary<string, AssetFinderRef> data)\n        {\n            refs = data;\n            SetupRefCallbacks();\n            dirty = true;\n            if (list != null) list.Clear();\n        }\n\n        //scene in scene\n        public AssetFinderRefDrawer ResetSceneInScene(GameObject[] objs)\n        {\n            // Set hasValidSelection based on whether we received valid GameObjects\n            hasValidSelection = objs != null && objs.Length > 0;\n            \n            refs = AssetFinderSceneRef.FindSceneInScene(objs);\n            SetupRefCallbacks();\n            dirty = true;\n            if (list != null) list.Clear();\n\n            return this;\n        }\n\n        public AssetFinderRefDrawer ResetSceneUseSceneObjects(GameObject[] objs)\n        {\n            // Set hasValidSelection based on whether we received valid GameObjects\n            hasValidSelection = objs != null && objs.Length > 0;\n            \n            refs = AssetFinderSceneRef.FindSceneUseSceneObjects(objs);\n            SetupRefCallbacks();\n            dirty = true;\n            if (list != null) list.Clear();\n\n            return this;\n        }\n\n        public AssetFinderRefDrawer ResetUnusedAsset(bool recursive = true)\n        {\n            List<AssetFinderAsset> lst = AssetFinderCache.Api.ScanUnused(recursive);\n\n            refs = lst.ToDictionary(x => x.guid, x => new AssetFinderRef(0, 1, x, null));\n            SetupRefCallbacks();\n            \n            // For unused assets, we always consider this a valid operation\n            hasValidSelection = true;\n            \n            dirty = true;\n            if (list != null) list.Clear();\n\n            return this;\n        }\n\n        public void RefreshSort()\n        {\n            if (list == null) return;\n            list.RemoveAll(item => item == null ||\n                 (item.isSceneRef \n                     ? (item.component == null)\n                     : (item.asset == null)\n                 ));\n            \n            if (list.Count == 0) return;\n            list.Sort((r1, r2) =>\n            {\n                bool isMixed = r1.isSceneRef != r2.isSceneRef;\n                if (isMixed)\n                {\n#if AssetFinderDEBUG\n\t\t\t\t\tvar sb = new System.Text.StringBuilder();\n\t\t\t\t\tsb.Append(\"r1: \" + r1.ToString());\n\t\t\t\t\tsb.AppendLine();\n\t\t\t\t\tsb.Append(\"r2: \" +r2.ToString());\n\t\t\t\t\tAssetFinderLOG.LogWarning($\"Mixed compared!\\n{sb}\");\n#endif\n\n                    int v1 = r1.isSceneRef ? 1 : 0;\n                    int v2 = r2.isSceneRef ? 1 : 0;\n                    return v2.CompareTo(v1);\n                }\n\n                if (r1.isSceneRef)\n                {\n                    var rs1 = (AssetFinderSceneRef)r1;\n                    var rs2 = (AssetFinderSceneRef)r2;\n\n                    return SortAsset(rs1.sceneFullPath, rs2.sceneFullPath,\n                        rs1.targetType, rs2.targetType,\n                        getSortMode() == Sort.Path);\n                }\n\n                if (r1.asset == null) return -1;\n                if (r2.asset == null) return 1;\n\n                return SortAsset(\n                    r1.asset.assetPath, r2.asset.assetPath,\n                    r1.asset.extension, r2.asset.extension,\n                    false\n                );\n            });\n            \n            groupDrawer.Reset(list,\n                rf =>\n                {\n                    if (rf == null) return null;\n                    return rf.isSceneRef ? rf.GetSceneObjId() : rf.asset?.guid;\n                }, GetGroup, SortGroup);\n        }\n\n        public bool isExclueAnyItem()\n        {\n            return excludeCount > 0;\n        }\n\n        private void ApplyFilter()\n        {\n            dirty = false;\n\n            if (refs == null) return;\n\n            if (list == null)\n            {\n                list = new List<AssetFinderRef>();\n            } else\n            {\n                list.Clear();\n            }\n\n            int minScore = searchTerm.Length;\n\n            string term1 = searchTerm;\n            if (!caseSensitive) term1 = term1.ToLower();\n\n            string term2 = term1.Replace(\" \", string.Empty);\n\n            excludeCount = 0;\n\n            foreach (KeyValuePair<string, AssetFinderRef> item in refs)\n            {\n                AssetFinderRef r = item.Value;\n\n                if (AssetFinderSetting.IsTypeExcluded(r.type))\n                {\n                    excludeCount++;\n                    continue; //skip this one\n                }\n\n                if (!showSearch || string.IsNullOrEmpty(searchTerm))\n                {\n                    r.matchingScore = 0;\n                    list.Add(r);\n                    continue;\n                }\n\n                //calculate matching score\n                string name1 = r.isSceneRef ? (r as AssetFinderSceneRef)?.sceneFullPath : r.asset.assetName;\n                if (!caseSensitive) name1 = name1?.ToLower();\n\n                string name2 = name1?.Replace(\" \", string.Empty);\n\n                int score1 = AssetFinderUnity.StringMatch(term1, name1);\n                int score2 = AssetFinderUnity.StringMatch(term2, name2);\n\n                r.matchingScore = Mathf.Max(score1, score2);\n                if (r.matchingScore > minScore) list.Add(r);\n            }\n\n            RefreshSort();\n        }\n\n        public void SetDirty()\n        {\n            dirty = true;\n        }\n\n        \n        public void InvalidateGroupCache()\n        {\n            gBookmarkCache.Clear();\n            Config.onCacheInvalidated?.Invoke();\n        }\n        \n        public string GetGroupForRef(AssetFinderRef rf)\n        {\n            return GetGroup(rf);\n        }\n        \n        public void ToggleAllItems()\n        {\n            if (refs == null) return;\n            \n            // Determine the new state based on majority rule\n            int bookmarkedCount = 0;\n            int totalCount = 0;\n            \n            foreach (var kvp in refs)\n            {\n                totalCount++;\n                if (AssetFinderBookmark.Contains(kvp.Value))\n                {\n                    bookmarkedCount++;\n                }\n            }\n            \n            bool newState = bookmarkedCount < totalCount / 2; // If less than half are bookmarked, bookmark all\n            \n            foreach (var kvp in refs)\n            {\n                if (newState)\n                {\n                    AssetFinderBookmark.Add(kvp.Value);\n                }\n                else\n                {\n                    AssetFinderBookmark.Remove(kvp.Value);\n                }\n            }\n            \n            InvalidateGroupCache();\n        }\n        \n        public void ToggleGroupItems(string groupLabel)\n        {\n            string[] ids = groupDrawer.GetChildren(groupLabel);\n            if (ids == null) return;\n            \n            // Toggle each sibling individually - if it's on, turn it off; if it's off, turn it on\n            for (var i = 0; i < ids.Length; i++)\n            {\n                if (!refs.TryGetValue(ids[i], out AssetFinderRef rf)) continue;\n                \n                if (AssetFinderBookmark.Contains(rf))\n                {\n                    AssetFinderBookmark.Remove(rf);\n                }\n                else\n                {\n                    AssetFinderBookmark.Add(rf);\n                }\n            }\n            \n            InvalidateGroupCache();\n        }\n        \n        public void SetGroupItemsState(string groupLabel, bool willBookmark)\n        {\n            string[] ids = groupDrawer.GetChildren(groupLabel);\n            if (ids == null) return;\n            \n            for (var i = 0; i < ids.Length; i++)\n            {\n                if (!refs.TryGetValue(ids[i], out AssetFinderRef rf)) continue;\n                \n                if (willBookmark)\n                {\n                    AssetFinderBookmark.Add(rf);\n                }\n                else\n                {\n                    AssetFinderBookmark.Remove(rf);\n                }\n            }\n        }\n\n        \n        private void HandleRefCtrlClick(AssetFinderRef rf)\n        {\n            // Toggle self and set all siblings to the same new state\n            bool newState = !rf.isSelected();\n            if (newState)\n            {\n                AssetFinderBookmark.Add(rf);\n            } else\n            {\n                AssetFinderBookmark.Remove(rf);\n            }\n            \n            // Then set all siblings to the same state\n            string groupName = GetGroupForRef(rf);\n            if (!string.IsNullOrEmpty(groupName) && groupDrawer.GetChildren(groupName) != null)\n            {\n                SetGroupItemsState(groupName, newState);\n            }\n            \n            InvalidateGroupCache();\n        }\n        \n        private void HandleRefAltClick(AssetFinderRef rf)\n        {\n            // Toggle all siblings in the same group\n            string groupName = GetGroupForRef(rf);\n            if (!string.IsNullOrEmpty(groupName) && groupDrawer.GetChildren(groupName) != null)\n            {\n                ToggleGroupItems(groupName);\n            }\n        }\n        \n        private void HandleRefShiftClick(AssetFinderRef rf)\n        {\n            // Toggle all items in all groups\n            ToggleAllItems();\n        }\n        \n        public void ClearSelection()\n        {\n            hasValidSelection = false;\n            refs = null;\n            if (list != null) list.Clear();\n            dirty = true;\n        }\n\n        private int SortAsset(string term11, string term12, string term21, string term22, bool swap)\n        {\n            //\t\t\tif (term11 == null) term11 = string.Empty;\n            //\t\t\tif (term12 == null) term12 = string.Empty;\n            //\t\t\tif (term21 == null) term21 = string.Empty;\n            //\t\t\tif (term22 == null) term22 = string.Empty;\n            int v1 = string.Compare(term11, term12, StringComparison.Ordinal);\n            int v2 = string.Compare(term21, term22, StringComparison.Ordinal);\n            return swap ? v1 == 0 ? v2 : v1 : v2 == 0 ? v1 : v2;\n        }\n\n        public Dictionary<string, AssetFinderRef> getRefs()\n        {\n            return refs;\n        }\n\n        internal class BookmarkInfo\n        {\n            public int count;\n            public int total;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderRefDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fcd5eb719592c5744b610afe347e2db4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderSceneRef.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderSceneRef : AssetFinderRef\n    {\n        internal static readonly Dictionary<string, Type> CacheType = new Dictionary<string, Type>();\n\n        private static Action<Dictionary<string, AssetFinderRef>> onFindRefInSceneComplete;\n        private static Dictionary<string, AssetFinderRef> refs = new Dictionary<string, AssetFinderRef>();\n        private static string[] cacheAssetGuids;\n        private GUIContent assetNameGC;\n        private GUIContent assetTypeGC;\n\n        public Func<bool> drawFullPath;\n        public string sceneFullPath = \"\";\n        public string scenePath = \"\";\n        public string targetType;\n        \n        public List<SceneRefInfo> sourceRefs;\n        public List<SceneRefInfo> backwardRefs;\n\n        public AssetFinderSceneRef(int index, int depth, AssetFinderAsset asset, AssetFinderAsset by) : base(index, depth, asset, by)\n        {\n            isSceneRef = false;\n            sourceRefs = new List<SceneRefInfo>();\n            backwardRefs = new List<SceneRefInfo>();\n            // Ensure tooltip always shows full path with proper slashes\n            string tooltipPath = asset?.assetPath ?? \"Unknown\";\n            assetNameGC = new GUIContent(asset?.assetName ?? \"Unknown\", tooltipPath);\n            assetTypeGC = new GUIContent(\"\");\n        }\n        \n        public AssetFinderSceneRef(int depth, UnityObject target) : base(0, depth, null, null)\n        {\n            component = target;\n            this.depth = depth;\n            isSceneRef = true;\n            sourceRefs = new List<SceneRefInfo>();\n            backwardRefs = new List<SceneRefInfo>();\n            InitializeTargetInfo(target);\n        }\n\n        void InitializeTargetInfo(UnityObject target)\n        {\n            if (target == null)\n            {\n                targetType = \"Missing\";\n                scenePath = \"\";\n                sceneFullPath = \"Missing Object\";\n                assetNameGC = new GUIContent(\"Missing Object\", \"Object has been destroyed\");\n                assetTypeGC = new GUIContent(\"Missing\");\n                return;\n            }\n\n            if (target is GameObject obj)\n            {\n                targetType = nameof(GameObject);\n                scenePath = AssetFinderUnity.GetGameObjectPath(obj, false);\n                // Add trailing slash if scenePath is not empty\n                string pathWithSlash = string.IsNullOrEmpty(scenePath) ? \"\" : scenePath + \"/\";\n                sceneFullPath = pathWithSlash + obj.name;\n                assetNameGC = new GUIContent(obj.name, sceneFullPath);\n                assetTypeGC = GUIContent.none;\n            }\n            else if (target is Component com)\n            {\n                targetType = component.GetType().Name;\n                scenePath = AssetFinderUnity.GetGameObjectPath(com.gameObject, false);\n                // Add trailing slash if scenePath is not empty\n                string pathWithSlash = string.IsNullOrEmpty(scenePath) ? \"\" : scenePath + \"/\";\n                sceneFullPath = pathWithSlash + com.gameObject.name;\n                assetNameGC = new GUIContent(com.gameObject.name, sceneFullPath);\n                assetTypeGC = new GUIContent(component.GetType().Name);\n            }\n        }\n        \n\n\n        public override bool isSelected()\n        {\n            return (component != null) && AssetFinderBookmark.Contains(component);\n        }\n\n        public void Draw(Rect r, AssetFinderRefDrawer.Mode groupMode, bool showDetails, bool drawFullPath = false)\n        {\n            r.xMin -= 12f;\n            r.xMax -= 12f;\n            \n            var margin = 2;\n            var pingRect = r;\n            Rect iconRect = GUI2.LeftRect(16f, ref r);\n            \n            // Right-click context menu for scene objects\n            if ((Event.current.type == EventType.MouseUp) && (Event.current.button == 1) && pingRect.Contains(Event.current.mousePosition))\n            {\n                var menu = new GenericMenu();\n                menu.AddItem(new GUIContent(\"Open\"), false, () => { if (component != null) EditorGUIUtility.PingObject(component); });\n                menu.AddItem(new GUIContent(\"Ping\"), false, () => { if (component != null) EditorGUIUtility.PingObject(component); });\n#if UNITY_2022_3_OR_NEWER\n                menu.AddItem(new GUIContent(\"Properties...\"), false, () => { if (component != null) EditorUtility.OpenPropertyEditor(component); });\n#else\n                menu.AddDisabledItem(new GUIContent(\"Properties...\"));\n#endif\n                menu.ShowAsContext();\n                Event.current.Use();\n            }\n            \n            var (icon, iconTooltip) = GetTargetIcon();\n            \n            // Calculate sizes based on whether we're showing full path\n            float pathW = 0f;\n            float nameW = 0f;\n            \n            if (drawFullPath && !string.IsNullOrEmpty(scenePath))\n            {\n                pathW = EditorStyles.miniLabel.CalcSize(AssetFinderGUIContent.FromString(scenePath + \"/\")).x;\n                nameW = EditorStyles.label.CalcSize(assetNameGC).x;\n            }\n            else\n            {\n                nameW = EditorStyles.label.CalcSize(assetNameGC).x;\n            }\n            \n            Rect pathRect = drawFullPath && pathW > 0 ? GUI2.LeftRect(pathW, ref r) : new Rect();\n            Rect nameRect = GUI2.LeftRect(nameW, ref r);\n            \n            float typeW = EditorStyles.miniLabel.CalcSize(assetTypeGC).x;\n            Rect typeRect = GUI2.LeftRect(typeW + 4f, ref r);\n            \n            pingRect.width = 16f + margin + pathW + nameW + typeW + 4f;\n            \n            DrawPingRect(pingRect);\n            DrawTargetIcon(iconRect, icon, iconTooltip);\n            DrawScenePath(pathRect, drawFullPath);\n            DrawTargetName(nameRect, assetNameGC);\n            DrawTargetType(typeRect, assetTypeGC);\n\n#if UNITY_2022_3_OR_NEWER\n            // Draw P only on hover and repaint on mouse move for responsiveness\n            Rect rowRect = new Rect(r.x, r.y, r.width, AssetFinderTheme.Current.TreeItemHeight);\n            bool isHover = rowRect.Contains(Event.current.mousePosition);\n            if (Event.current.type == EventType.MouseMove)\n            {\n                var focused = EditorWindow.focusedWindow;\n                if (focused != null) focused.Repaint();\n            }\n            if (isHover)\n            {\n                var propRect = new Rect(r.x + r.width - 22f, r.y, 22f, r.height);\n                r.width -= 22f;\n                float miniH = 16f;\n                propRect.y += Mathf.Floor((AssetFinderTheme.Current.TreeItemHeight - miniH) / 2f);\n                propRect.height = miniH;\n                if (GUI.Button(propRect, new GUIContent(\"P\", \"Open Properties\"), EditorStyles.miniButton))\n                {\n                    if (component != null) EditorUtility.OpenPropertyEditor(component);\n                }\n            }\n#endif\n\n            if (AssetFinderSetting.ShowUsedByClassed)\n            {\n                DrawReferenceIcons(r);\n            }\n        }\n\n        (Texture icon, string tooltip) GetTargetIcon()\n        {\n            if (component == null) return (null, \"\");\n            \n            if (component is GameObject go)\n                return (EditorGUIUtility.ObjectContent(go, typeof(GameObject)).image, \"GameObject\");\n            if (component is Component comp)\n                return (EditorGUIUtility.ObjectContent(comp, comp.GetType()).image, comp.GetType().Name);\n            \n            return (EditorGUIUtility.ObjectContent(component, component.GetType()).image, component.GetType().Name);\n        }\n\n        void DrawTargetIcon(Rect iconRect, Texture icon, string iconTooltip)\n        {\n            if (icon != null)\n            {\n                var iconContent = new GUIContent(icon, iconTooltip);\n                GUI.Label(iconRect, iconContent, EditorStyles.label);\n            }\n        }\n\n        void DrawScenePath(Rect pathRect, bool drawFullPath)\n        {\n            if (!drawFullPath || string.IsNullOrEmpty(scenePath)) return;\n            \n            Color c = GUI.color;\n            GUI.color = new Color(c.r, c.g, c.b, c.a * 0.5f); // Dim the path like Unity's Project panel\n            GUI.Label(pathRect, AssetFinderGUIContent.FromString(scenePath + \"/\"), EditorStyles.miniLabel);\n            GUI.color = c;\n        }\n\n        void DrawTargetName(Rect nameRect, GUIContent displayContent)\n        {\n            if (isSelected())\n            {\n                Color c = GUI.color;\n                GUI.color = GUI.skin.settings.selectionColor;\n                GUI.DrawTexture(nameRect, EditorGUIUtility.whiteTexture);\n                GUI.color = c;\n            }\n            GUI.Label(nameRect, displayContent, EditorStyles.label);\n        }\n\n        void DrawTargetType(Rect typeRect, GUIContent typeContent)\n        {\n            if (!string.IsNullOrEmpty(typeContent.text))\n            {\n                // Always dim component type, no hover effects\n                Color c = GUI.color;\n                GUI.color = new Color(c.r, c.g, c.b, c.a * 0.6f);\n                GUI.Label(typeRect, typeContent, EditorStyles.miniLabel);\n                GUI.color = c;\n            }\n        }\n\n        void DrawReferenceIcons(Rect r)\n        {\n            if (sourceRefs?.Count > 0)\n            {\n                DrawComponentIcons(r, sourceRefs, (refInfo, iconRect) => {\n                    EditorGUIUtility.PingObject(refInfo.sourceComponent);\n                    AssetFinderUnity.PingAndHighlight(refInfo.sourceComponent, refInfo.propertyPath); \n                    GUIUtility.ExitGUI();\n                });\n            }\n            else if (backwardRefs?.Count > 0)\n            {\n                DrawComponentIcons(r, backwardRefs, (refInfo, iconRect) => {\n                    EditorGUIUtility.PingObject(refInfo.sourceComponent);\n                    AssetFinderUnity.PingAndHighlight(refInfo.sourceComponent, refInfo.propertyPath); \n                    GUIUtility.ExitGUI();\n                });\n            }\n        }\n\n        void DrawComponentIcons(Rect r, List<SceneRefInfo> refInfos, Action<SceneRefInfo, Rect> onIconClick)\n        {\n            if (refInfos == null || refInfos.Count == 0) return;\n            \n            float width = 18f;\n            float totalWidth = width * refInfos.Count;\n            \n            if (refInfos.Count == 1)\n            {\n                var refInfo = refInfos[0];\n                var beautifiedPath = BeautifyPropertyPath(refInfo.propertyPath);\n                var labelWidth = EditorStyles.miniLabel.CalcSize(new GUIContent(beautifiedPath)).x;\n                totalWidth += labelWidth + 4f;\n            }\n            \n            float startX = r.x + r.width - totalWidth;\n            \n            for (int i = 0; i < refInfos.Count; i++)\n            {\n                var refInfo = refInfos[i];\n                var targetComponent = refInfo.GetTargetComponent();\n                if (targetComponent == null) continue;\n                \n                float currentX = startX;\n                \n                if (refInfos.Count == 1)\n                {\n                    var beautifiedPath = BeautifyPropertyPath(refInfo.propertyPath);\n                    var labelWidth = EditorStyles.miniLabel.CalcSize(new GUIContent(beautifiedPath)).x;\n                    var labelRect = new Rect(currentX, r.y, labelWidth, r.height);\n                    \n                    // Always dim property path, no hover effects\n                    Color c = GUI.color;\n                    GUI.color = new Color(c.r, c.g, c.b, c.a * 0.6f);\n                    GUI.Label(labelRect, beautifiedPath, EditorStyles.miniLabel);\n                    GUI.color = c;\n                    \n                    currentX += labelWidth + 4f;\n                }\n                else\n                {\n                    currentX += i * width;\n                }\n                \n                var iconRect = new Rect(currentX, r.y, width, r.height);\n                var icon = EditorGUIUtility.ObjectContent(targetComponent, targetComponent.GetType()).image;\n                var tooltipText = refInfo.IsBackwardRef \n                    ? refInfo.propertyPath \n                    : $\"{refInfo.sourceComponent.GetType().Name}.{refInfo.propertyPath}\";\n                var content = new GUIContent(icon, tooltipText);\n                \n                GUI.Label(iconRect, content);\n                if (GUI.Button(iconRect, content, EditorStyles.label))\n                {\n                    onIconClick(refInfo, iconRect);\n                }\n            }\n        }\n\n        string BeautifyPropertyPath(string propertyPath)\n        {\n            if (string.IsNullOrEmpty(propertyPath)) return \"\";\n            \n            string result = propertyPath;\n            result = result.Replace(\".Array.data[\", \"[\");\n            result = result.Replace(\"].Array.data[\", \"][\");\n            \n            return result;\n        }\n\n        void DrawPingRect(Rect pingRect)\n        {\n            bool selected = isSelected();\n            if ((Event.current.type == EventType.MouseDown) && (Event.current.button == 0))\n            {\n                if (pingRect.Contains(Event.current.mousePosition))\n                {\n                    if (Event.current.control || Event.current.command)\n                    {\n                        if (selected)\n                        {\n                            AssetFinderBookmark.Remove(this);\n                        } else\n                        {\n                            AssetFinderBookmark.Add(this);\n                        }\n                    } else\n                    {\n                        // Set smart lock state for scene ping to allow selection change\n                        var fr2Window = EditorWindow.GetWindow<AssetFinderWindowAll>(false, null, false);\n                        if (fr2Window != null && fr2Window.smartLock != null)\n                        {\n                            fr2Window.smartLock.SetPingLockState(AssetFinderSmartLock.PingLockState.Scene);\n                        }\n                        \n                        EditorGUIUtility.PingObject(component);\n                    }\n                    Event.current.Use();\n                }\n            }\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindSceneUseSceneObjects(GameObject[] targets)\n        {\n            return AssetFinderSceneCache.FindSceneUseSceneObjects(targets);\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindSceneBackwardReferences(GameObject[] targets)\n        {\n            return AssetFinderSceneCache.FindSceneBackwardReferences(targets);\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindSceneInScene(GameObject[] targets)\n        {\n            return AssetFinderSceneCache.FindSceneInScene(targets);\n        }\n\n        public static Dictionary<string, AssetFinderRef> FindRefInScene(\n            string[] assetGUIDs, bool depth,\n            Action<Dictionary<string, AssetFinderRef>> onComplete)\n        {\n            cacheAssetGuids = assetGUIDs;\n            onFindRefInSceneComplete = onComplete;\n            if (AssetFinderSceneCache.isReady)\n            {\n                FindRefInScene();\n            } else\n            {\n                AssetFinderSceneCache.onReady -= FindRefInScene;\n                AssetFinderSceneCache.onReady += FindRefInScene;\n            }\n\n            return refs;\n        }\n\n        private static void FindRefInScene()\n        {\n            if (refs == null) refs = new Dictionary<string, AssetFinderRef>();\n            else refs.Clear(); // Reuse existing dictionary\n            \n            for (var i = 0; i < cacheAssetGuids.Length; i++)\n            {\n                AssetFinderAsset asset = AssetFinderCache.Api.Get(cacheAssetGuids[i]);\n                if (asset == null) continue;\n\n                Add(refs, asset, 0);\n                ApplyFilter(refs, asset);\n            }\n\n            if (onFindRefInSceneComplete != null) onFindRefInSceneComplete(refs);\n            AssetFinderSceneCache.onReady -= FindRefInScene;\n        }\n\n        private static void ApplyFilter(Dictionary<string, AssetFinderRef> refs, AssetFinderAsset asset)\n        {\n            string targetPath = AssetDatabase.GUIDToAssetPath(asset.guid);\n            if (string.IsNullOrEmpty(targetPath)) return;\n\n            if (targetPath != asset.assetPath) asset.MarkAsDirty();\n\n            UnityObject target = AssetDatabase.LoadAssetAtPath(targetPath, typeof(UnityObject));\n            if (target == null) return;\n\n            if (target is GameObject)\n            {\n                foreach (GameObject item in AssetFinderUnity.getAllObjsInCurScene())\n                {\n                    if (AssetFinderUnity.CheckIsPrefab(item))\n                    {\n                        string itemGUID = AssetFinderUnity.GetPrefabParent(item);\n                        if (itemGUID == asset.guid) Add(refs, item, 1);\n                    }\n                }\n            }\n\n            // Search through all cached components for references to this asset\n            foreach (var cacheEntry in AssetFinderSceneCache.Api.cache)\n            {\n                foreach (var hashValue in cacheEntry.Value)\n                {\n                    if (targetPath == AssetDatabase.GetAssetPath(hashValue.target))\n                    {\n                        Add(refs, cacheEntry.Key, 1);\n                        break;\n                    }\n                }\n            }\n        }\n\n        private static void Add(Dictionary<string, AssetFinderRef> refs, AssetFinderAsset asset, int depth)\n        {\n            string targetId = asset.guid;\n            if (!refs.ContainsKey(targetId)) refs.Add(targetId, new AssetFinderRef(0, depth, asset, null));\n        }\n\n        private static void Add(Dictionary<string, AssetFinderRef> refs, UnityObject target, int depth)\n        {\n            if (target == null) return;\n            var targetId = target.GetInstanceID().ToString();\n            if (!refs.ContainsKey(targetId)) refs.Add(targetId, new AssetFinderSceneRef(depth, target));\n        }\n    }\n    \n\n    \n\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderSceneRef.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 22ef8041c6ba839489532b86afe8c941\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderTreeUI2.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderTreeUI2\n    {\n        internal Drawer drawer;\n        public float itemPaddingRight = 0f;\n        public float itemPaddingLeft = 0f;\n        private Vector2 position;\n        internal TreeItem rootItem;\n        internal Rect visibleRect;\n\n        public AssetFinderTreeUI2(Drawer drawer)\n        {\n            this.drawer = drawer;\n        }\n\n        public void Reset(params string[] root)\n        {\n            position = Vector2.zero;\n\n            rootItem = new TreeItem\n            {\n                tree = this,\n                id = \"$root\",\n                height = 0,\n                depth = -1,\n                _isOpen = true,\n                highlight = false,\n                childCount = root.Length\n            };\n\n            rootItem.RefreshChildren(root);\n            rootItem.DeepOpen();\n        }\n\n        public void Draw(Rect rect)\n        {\n            if (rect.width > 0) visibleRect = rect;\n\n            var contentRect = new Rect(0f, 0f, 1f, rootItem.childrenHeight + AssetFinderTheme.Current.TreeContentPadding * 2);\n            bool noScroll = contentRect.height < visibleRect.height;\n            if (noScroll) position = Vector2.zero;\n\n            var minY = (int)position.y;\n            var maxY = (int)(position.y + visibleRect.height);\n            contentRect.x -= AssetFinderSetting.TreeIndent;\n\n            TreeItem.DrawCall = 0;\n            TreeItem.DrawRender = 0;\n            position = GUI.BeginScrollView(visibleRect, position, contentRect);\n            {\n                var theme = AssetFinderTheme.Current;\n                var r = new Rect(theme.TreeContentPadding + itemPaddingLeft, theme.TreeContentPadding, \n                    rect.width - (noScroll ? theme.CompactSpacing : theme.ScrollBarWidth) - itemPaddingRight - theme.TreeContentPadding * 2 - itemPaddingLeft, \n                    theme.TreeItemHeight);\n                var index = 0;\n                rootItem.Draw(ref index, ref r, minY, maxY);\n            }\n\n            GUI.EndScrollView();\n        }\n\n        public void DrawLayout()\n        {\n            EventType evtType = Event.current.type;\n            var theme = AssetFinderTheme.Current;\n            Rect r = GUILayoutUtility.GetRect(1f, Screen.width, theme.TreeItemHeight, Screen.height);\n\n            if (evtType != EventType.Layout) visibleRect = r;\n\n            Draw(visibleRect);\n        }\n\n        public bool NoScroll()\n        {\n            return rootItem.childrenHeight < visibleRect.height;\n        }\n\n        // ------------------------ DELEGATE --------------\n\n        internal class Drawer\n        {\n            public virtual int GetHeight(string id)\n            {\n                return (int)AssetFinderTheme.Current.TreeItemHeight;\n            }\n\n            public virtual int GetChildCount(string id)\n            {\n                return 0;\n            }\n\n            public virtual string[] GetChildren(string id)\n            {\n                return null;\n            }\n\n            public virtual void Draw(Rect r, TreeItem item)\n            {\n                GUI.Label(r, AssetFinderGUIContent.From(item.id));\n            }\n        }\n\n        internal class GroupDrawer : Drawer\n        {\n            public readonly Action<Rect, string, int> drawGroup;\n            public readonly Action<Rect, string> drawItem;\n            private Dictionary<string, List<string>> groupDict;\n\n            public bool hideGroupIfPossible;\n            internal AssetFinderTreeUI2 tree;\n\n            public GroupDrawer(Action<Rect, string, int> drawGroup, Action<Rect, string> drawItem)\n            {\n                this.drawItem = drawItem;\n                this.drawGroup = drawGroup;\n            }\n\n            public bool hasChildren => (tree != null) && (tree.rootItem.childCount > 0);\n\n            public bool hasValidTree => (groupDict != null) && (tree != null);\n\n            // ----------------- TREE WRAPPER ------------------\n            public bool TreeNoScroll()\n            {\n                return tree.NoScroll();\n            }\n\n\n            public void Reset<T>(\n                List<T> items, Func<T, string> idFunc, Func<T, string> groupFunc,\n                Action<List<string>> customGroupSort = null)\n            {\n                groupDict = new Dictionary<string, List<string>>();\n\n                for (var i = 0; i < items.Count; i++)\n                {\n                    List<string> list;\n\n                    string groupName = groupFunc(items[i]);\n                    if (groupName == null) continue; // do not exclude groupName string.Empty\n\n                    string itemId = idFunc(items[i]);\n                    if (string.IsNullOrEmpty(itemId)) continue; // ignore items without id\n\n                    if (!groupDict.TryGetValue(groupName, out list))\n                    {\n                        list = new List<string>();\n                        groupDict.Add(groupName, list);\n                    }\n\n                    list.Add(itemId);\n                }\n\n                if (tree == null) tree = new AssetFinderTreeUI2(this);\n\n                List<string> groups = groupDict.Keys.ToList();\n\n                if (hideGroupIfPossible && (groups.Count == 1)) //single group : Flat list\n                {\n                    List<string> v = groupDict[groups[0]];\n                    tree.Reset(v.ToArray());\n                    groupDict.Clear();\n                } else\n                { //multiple groups\n                    if (customGroupSort != null)\n                    {\n                        customGroupSort(groups);\n                    } else\n                    {\n                        groups.Sort();\n                    }\n\n                    tree.Reset(groups.ToArray());\n                }\n            }\n\n            public void Draw(Rect r)\n            {\n                if (tree != null) tree.Draw(r);\n            }\n\n            public void DrawLayout()\n            {\n                if (tree != null) tree.DrawLayout();\n            }\n\n            // ----------------- DRAWER WRAPPER ------------------\n\n            public override int GetChildCount(string id)\n            {\n                if (string.IsNullOrEmpty(id) || groupDict == null) return 0;\n                return groupDict.TryGetValue(id, out List<string> group) ? group.Count : 0;\n\n            }\n\n            public override string[] GetChildren(string id)\n            {\n                if (groupDict == null) return null;\n                return groupDict.TryGetValue(id, out List<string> group) ? group.ToArray() : null;\n\n            }\n\n            public override void Draw(Rect r, TreeItem item)\n            {\n                if (groupDict != null && groupDict.TryGetValue(item.id, out List<string> group))\n                {\n                    drawGroup(r, item.id, item.childCount);\n                    return;\n                }\n\n                drawItem(r, item.id);\n            }\n        }\n\n        // ------------------------ TreeItem2 --------------\n\n        internal class TreeItem\n        {\n            public static int DrawCall;\n            public static int DrawRender;\n\n            internal bool _isOpen;\n\n            public int childCount;\n            public List<TreeItem> children;\n            public int childrenHeight;\n            public int depth; // item depth\n\n            public int height;\n            public bool highlight;\n\n            public string id; // item id\n\n            internal TreeItem parent;\n\n            //static Color COLOR\t= new Color(0f, 0f, 0f, 0.05f);\n\n            internal AssetFinderTreeUI2 tree;\n\n            public bool IsOpen\n            {\n                get => _isOpen;\n                set\n                {\n                    if (_isOpen == value || childCount == 0) return;\n\n                    _isOpen = value;\n\n                    if (_isOpen)\n                    {\n                        if (children == null) RefreshChildren(tree.drawer.GetChildren(id));\n\n                        //Update height for all parents\n                        TreeItem p = parent;\n                        while (p != null)\n                        {\n                            p.childrenHeight += childrenHeight;\n                            p = p.parent;\n                        }\n                    } else\n                    {\n                        //Update height for all parents\n                        TreeItem p = parent;\n                        while (p != null)\n                        {\n                            p.childrenHeight -= childrenHeight;\n                            p = p.parent;\n                        }\n                    }\n                }\n            }\n\n            internal void DeepOpen()\n            {\n                IsOpen = true;\n                if (children == null) return;\n\n                for (var i = 0; i < children.Count; i++)\n                {\n                    children[i].DeepOpen();\n                }\n            }\n\n            internal void Draw(ref int index, ref Rect rect, int minY, int maxY)\n            {\n                DrawCall++;\n\n                float min = rect.y;\n                float max = rect.y + height;\n                bool interMin = (min >= minY) && (min <= maxY);\n                bool interMax = (max >= minY) && (max <= maxY);\n\n                if ((height > 0) && (interMin || interMax))\n                {\n                    DrawRender++;\n                    rect.height = height;\n\n                    if ((index % 2 == 1) && AssetFinderSetting.AlternateRowColor)\n                    {\n                        Color o = GUI.color;\n                        GUI.color = AssetFinderSetting.RowColor;\n\n                        // GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);\n                        GUI.DrawTexture(new Rect(rect.x - AssetFinderSetting.TreeIndent, rect.y, rect.width, rect.height),\n                            EditorGUIUtility.whiteTexture);\n                        GUI.color = o;\n                    }\n\n                    var theme = AssetFinderTheme.Current;\n                    float x = (depth + 1) * theme.TreeIndentSize;\n                    tree.drawer.Draw(new Rect(x, rect.y, rect.width - x, rect.height), this);\n\n                    if (childCount > 0)\n                    {\n                        IsOpen = GUI.Toggle(new Rect(rect.x + x - theme.TreeIndentSize, rect.y, theme.TreeToggleSize, theme.TreeToggleSize), \n                            IsOpen, GUIContent.none, EditorStyles.foldout);\n                    }\n\n                    index++;\n                    rect.y += height + theme.TreeItemSpacing;\n                } else\n                {\n                    rect.y += height + AssetFinderTheme.Current.TreeItemSpacing;\n                }\n\n                if (_isOpen && (rect.y <= maxY)) //draw children\n                {\n                    for (var i = 0; i < children.Count; i++)\n                    {\n                        children[i].Draw(ref index, ref rect, minY, maxY);\n                        if (rect.y > maxY) break;\n                    }\n                }\n            }\n\n            internal void RefreshChildren(string[] childrenIDs)\n            {\n                childCount = childrenIDs.Length;\n                childrenHeight = 0;\n                children = new List<TreeItem>();\n\n                for (var i = 0; i < childCount; i++)\n                {\n                    string itemId = childrenIDs[i];\n\n                    var item = new TreeItem\n                    {\n                        tree = tree,\n                        parent = this,\n\n                        id = itemId,\n                        depth = depth + 1,\n                        highlight = false,\n\n                        height = tree.drawer.GetHeight(itemId),\n                        childCount = tree.drawer.GetChildCount(itemId)\n                    };\n\n                    childrenHeight += item.height + (int)AssetFinderTheme.Current.TreeItemSpacing;\n                    children.Add(item);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI/AssetFinderTreeUI2.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fee07110472e29344bfcab27b4a7725a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/TreeUI.meta",
    "content": "fileFormatVersion: 2\nguid: eff03ad31a264fe8863d406929204090\ntimeCreated: 1746366439"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderDeleteButton.cs",
    "content": "using System;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderDeleteButton\n    {\n        public string confirmMessage;\n        public GUIContent deleteLabel;\n        public bool hasConfirm;\n        public string warningMessage;\n\n        public bool Draw(Action onConfirmDelete)\n        {\n            GUILayout.BeginHorizontal();\n            {\n                EditorGUILayout.HelpBox(warningMessage, MessageType.Warning);\n                GUILayout.BeginVertical();\n                {\n                    GUILayout.Space(2f);\n                    hasConfirm = GUILayout.Toggle(hasConfirm, confirmMessage);\n                    EditorGUI.BeginDisabledGroup(!hasConfirm);\n                    {\n                        GUI2.BackgroundColor(() =>\n                        {\n                            if (GUILayout.Button(deleteLabel, EditorStyles.miniButton))\n                            {\n                                hasConfirm = false;\n                                onConfirmDelete();\n                                GUIUtility.ExitGUI();\n                            }\n                        }, GUI2.darkRed, 0.8f);\n                    }\n                    EditorGUI.EndDisabledGroup();\n                }\n                GUILayout.EndVertical();\n            }\n            GUILayout.EndHorizontal();\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderDeleteButton.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 37ca5ee8134e93741a29ac2b528d5096\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderEnumDrawer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderEnumDrawer\n    {\n\n        [NonSerialized] internal EnumInfo AssetFinderenum;\n        public int index;\n        public string tooltip;\n\n        public bool DrawLayout<T>(ref T enumValue, params GUILayoutOption[] options)\n        {\n            if (AssetFinderenum == null)\n            {\n                Type enumType = enumValue.GetType();\n                AssetFinderenum = EnumInfo.Get(enumType);\n                index = AssetFinderenum.IndexOf(enumValue);\n            }\n\n            if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout)\n            {\n                GUILayout.Label(AssetFinderenum.contents[index], EditorStyles.toolbarPopup, options);\n                return false;\n            }\n\n            int nIndex = EditorGUILayout.Popup(index, AssetFinderenum.contents, EditorStyles.toolbarPopup, options);\n            if (nIndex == index)\n            {\n                // Debug.LogWarning($\"Same index: {nIndex} | {index}\");\n                return false;\n            }\n            index = nIndex;\n            enumValue = (T)AssetFinderenum.ValueAt(index);\n            return true;\n        }\n\n        public bool Draw<T>(Rect rect, ref T enumValue)\n        {\n            if (AssetFinderenum == null)\n            {\n                Type enumType = enumValue.GetType();\n                AssetFinderenum = EnumInfo.Get(enumType);\n                index = AssetFinderenum.IndexOf(enumValue);\n            }\n\n            if (Event.current.type == EventType.Layout) return false;\n            if (Event.current.type == EventType.Repaint)\n            {\n                GUIContent content = AssetFinderenum.contents[index];\n                if (!string.IsNullOrEmpty(tooltip)) content.tooltip = tooltip;\n                GUI.Label(rect, content, EditorStyles.toolbarPopup);\n                return false;\n            }\n\n            int nIndex = EditorGUI.Popup(rect, index, AssetFinderenum.contents, EditorStyles.toolbarPopup); //, options\n            if (nIndex != index)\n            {\n                index = nIndex;\n                enumValue = (T)AssetFinderenum.ValueAt(index);\n                return true;\n            }\n\n            return false;\n        }\n        internal class EnumInfo\n        {\n            public static readonly Dictionary<Type, EnumInfo> cache = new Dictionary<Type, EnumInfo>();\n            public readonly GUIContent[] contents;\n            public readonly Array values;\n            public EnumInfo(Type enumType)\n            {\n                string[] names = Enum.GetNames(enumType);\n\n                values = Enum.GetValues(enumType);\n                contents = new GUIContent[names.Length];\n                for (var i = 0; i < names.Length; i++)\n                {\n                    contents[i] = AssetFinderGUIContent.FromString(names[i]);\n                }\n            }\n\n            public EnumInfo(params object[] enumValues)\n            {\n                values = enumValues;\n                contents = new GUIContent[values.Length];\n                for (var i = 0; i < values.Length; i++)\n                {\n                    contents[i] = AssetFinderGUIContent.FromString(enumValues[i].ToString());\n                }\n            }\n            public static EnumInfo Get(Type type)\n            {\n                if (cache.TryGetValue(type, out EnumInfo result))\n                {\n                    return result;\n                }\n\n                result = new EnumInfo(type);\n                cache.Add(type, result);\n                return result;\n            }\n\n            public int IndexOf(object enumValue)\n            {\n                return Array.IndexOf(values, enumValue);\n            }\n\n            public object ValueAt(int index)\n            {\n                return values.GetValue(index);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderEnumDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: de6985c1c8c545540b3e3e792b255328\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderGUIContent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class AssetFinderGUIContent\n    {\n        // Cache to improve performance\n        private static readonly Dictionary<string, GUIContent> stringMap = new Dictionary<string, GUIContent>();\n        private static readonly Dictionary<string, GUIContent> tooltipMap = new Dictionary<string, GUIContent>();\n        private static readonly Dictionary<int, GUIContent> intMap = new Dictionary<int, GUIContent>();\n        private static readonly Dictionary<Texture, GUIContent> texMap = new Dictionary<Texture, GUIContent>();\n        private static readonly Dictionary<string, GUIContent> stringTexMap = new Dictionary<string, GUIContent>();\n        private static readonly Dictionary<Type, GUIContent> typeMap = new Dictionary<Type, GUIContent>();\n\n        public static void Release()\n        {\n            stringMap.Clear();\n            texMap.Clear();\n        }\n\n        public static GUIContent FromString(string title, string tooltip = null)\n        {\n            if (string.IsNullOrEmpty(title))\n            {\n                AssetFinderLOG.LogWarning(\"Title is null or empty!\");\n                return GUIContent.none;\n            }\n\n            if (stringMap.TryGetValue(title, out GUIContent result)) return result;\n            result = new GUIContent(title, tooltip);\n            stringMap.Add(title, result);\n            return result;\n        }\n\n        public static GUIContent FromType(Type t, string tooltip = null)\n        {\n            if (typeMap.TryGetValue(t, out GUIContent result)) return result;\n            result = new GUIContent(EditorGUIUtility.ObjectContent(null, t).image, tooltip);\n            typeMap.Add(t, result);\n            return result;\n        }\n\n        public static GUIContent Tooltip(string tooltip)\n        {\n            if (tooltipMap.TryGetValue(tooltip, out GUIContent result)) return result;\n            result = new GUIContent(string.Empty, tooltip);\n            tooltipMap.Add(tooltip, result);\n            return result;\n        }\n\n        public static GUIContent From(object data)\n        {\n            if (data is GUIContent content) return content;\n            if (data is Texture texture) return FromTexture(texture);\n            if (data is string s) return FromString(s);\n            if (data is Type t) return FromType(t);\n            return data is int i ? FromInt(i) : GUIContent.none;\n        }\n\n        public static GUIContent FromInt(int val)\n        {\n            if (intMap.TryGetValue(val, out GUIContent result)) return result;\n\n            var str = val.ToString();\n            result = FromString(str);\n            intMap.Add(val, result);\n            return result;\n        }\n\n        public static GUIContent FromTexture(Texture tex, string tooltip = null)\n        {\n            if (texMap.TryGetValue(tex, out GUIContent result)) return result;\n            result = new GUIContent(tex, tooltip);\n            texMap.Add(tex, result);\n            return result;\n        }\n\n        public static GUIContent From(string title, Texture tex, string tooltip = null)\n        {\n            if (stringTexMap.TryGetValue(title, out GUIContent result)) return result;\n            result = new GUIContent(title, tex, tooltip);\n            stringTexMap.Add(title, result);\n            return result;\n        }\n\n        public static GUIContent[] FromArrayLabelIcon(params object[] data)\n        {\n            var result = new List<GUIContent>();\n            for (var i = 0; i < data.Length; i++)\n            {\n                result.Add(From(data[0].ToString(), (Texture)data[1]));\n            }\n            return result.ToArray();\n        }\n\n        public static GUIContent[] FromArray(params object[] data)\n        {\n            var result = new List<GUIContent>();\n            foreach (object item in data)\n            {\n                if (item is string s)\n                {\n                    result.Add(FromString(s));\n                    continue;\n                }\n\n                if (item is Texture texture)\n                {\n                    result.Add(FromTexture(texture));\n                    continue;\n                }\n\n                if (item is GUIContent content)\n                {\n                    result.Add(content);\n                    continue;\n                }\n\n                AssetFinderLOG.LogWarning(\"Unsupported type: \" + item);\n            }\n\n            return result.ToArray();\n        }\n\n        public static GUIContent[] FromEnum(Type enumType)\n        {\n            Array values = Enum.GetValues(enumType);\n            var result = new List<GUIContent>();\n            foreach (object item in values)\n            {\n                result.Add(FromString(item.ToString()));\n            }\n            return result.ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderGUIContent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c9c752a5ea34866408787cdd5356b47c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderIcon.cs",
    "content": "using System.Reflection;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static class AssetFinderIcon\n    {\n        public static GUIContent Lock => TryGet(\"LockIcon-On\", \"Click to unlock\");\n        public static GUIContent Unlock => TryGet(\"LockIcon\", \"Click to lock\");\n\n#if UNITY_2019_3_OR_NEWER\n        public static GUIContent Refresh => TryGet(\"d_Refresh@2x\");\n#else\n    public static GUIContent Refresh { get { return TryGet(\"LookDevResetEnv\"); } }\n#endif\n\n        public static GUIContent Selection => TryGet(\"d_Selectable Icon\");\n        public static GUIContent Details => TryGet(\"d_UnityEditor.SceneHierarchyWindow\");\n        public static GUIContent Favorite => TryGet(\"d_Favorite\");\n        public static GUIContent Setting => TryGet(\"d_SettingsIcon\");\n        public static GUIContent Ignore => TryGet(\"ShurikenCheckMarkMixed\");\n        public static GUIContent Plus => TryGet(\"ShurikenPlus\");\n\n        public static GUIContent Visibility => TryGet(\"ClothInspector.ViewValue\");\n#if UNITY_2019_3_OR_NEWER\n        public static GUIContent Panel => TryGet(\"VerticalSplit\");\n#else\n    public static GUIContent Panel { get { return TryGet(\"d_LookDevSideBySide\"); } }\n#endif\n        public static GUIContent Layout => TryGet(\"FreeformLayoutGroup Icon\");\n        public static GUIContent Sort => TryGet(\"AlphabeticalSorting\"); //d_DefaultSorting\n\n        public static GUIContent CustomTool => TryGet(\"CustomTool\", \"Advanced Tools\");\n\n#if UNITY_2019_3_OR_NEWER\n        public static GUIContent Filter => TryGet(\"d_ToggleUVOverlay@2x\");\n#else\n        public static GUIContent Filter { get { return TryGet(\"LookDevSplit\"); } }\n#endif\n\n        public static GUIContent Group => TryGet(\"EditCollider\");\n        public static GUIContent Delete => TryGet(\"d_TreeEditor.Trash\");\n        public static GUIContent Split => TryGet(\"VerticalSplit\");\n        public static GUIContent Close => TryGet(\"LookDevClose\");\n        public static GUIContent Prefab => TryGet(\"d_Prefab Icon\");\n        public static GUIContent Asset => TryGet(\"Folder Icon\");\n        public static GUIContent Warning => TryGet(\"console.warnicon\");\n        public static GUIContent Info => TryGet(\"console.warnicon\");\n        public static GUIContent Filesize => TryGet(\"Download-Available@2x\", \"Show File Size\");\n        public static GUIContent FileExtension => TryGet(\"d_curvekeyframeweighted\", \"Show File Extension\");\n\n        public static GUIContent AssetBundle => TryGet(\"CloudConnect\");\n        public static GUIContent Script => TryGet(\"dll Script Icon\");\n        public static GUIContent Material => TryGet(\"d_TreeEditor.Material\");\n        public static GUIContent Scene => TryGet(\"UnityLogo\");\n#if UNITY_2017_1_OR_NEWER\n        public static GUIContent Atlas => TryGet(\"SpriteAtlas Icon\");\n#endif\n        public static GUIContent Folder => TryGet(\"Project\");\n\n        public static GUIContent FullPath => TryGet(\"UnityEditor.HierarchyWindow\", \"Show full asset path\");\n        public static GUIContent Hierarchy => TryGet(\"UnityEditor.HierarchyWindow\");\n\n        public static GUIContent Organize => TryGet(\"FolderEmpty Icon\");\n\n        private static readonly MethodInfo _loadIconMethod = typeof(EditorGUIUtility)\n            .GetMethod(\"LoadIcon\", BindingFlags.Static | BindingFlags.NonPublic);\n        \n        private static readonly Dictionary<string, GUIContent> _cache = new Dictionary<string, GUIContent>();\n        private static GUIContent TryGet(string id, string tooltip = null)\n        {\n            if (_cache.TryGetValue(id, out GUIContent result)) return result ?? GUIContent.none;\n            Texture2D tex = null;\n            if (_loadIconMethod != null)\n                tex = _loadIconMethod.Invoke(null, new object[] { id }) as Texture2D;\n            GUIContent icon = tex != null\n                ? new GUIContent(tex)\n                : new GUIContent(Texture2D.whiteTexture);\n            if (!string.IsNullOrEmpty(tooltip)) icon.tooltip = tooltip;\n            _cache.Add(id, icon);\n            return icon;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderIcon.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b55e5a87ccb7972448444ff9b63a7a24\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderObjectDrawer.cs",
    "content": "using System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderObjectDrawer\n    {\n        private static readonly Dictionary<UnityObject, GUIContent> contentMap = new Dictionary<UnityObject, GUIContent>();\n        private static GUIStyle objectFieldStyle;\n\n        public void DrawOnly(Rect rect, UnityObject target)\n        {\n            GUIContent content;\n\n            if (target == null)\n            {\n                content = AssetFinderGUIContent.From(\"(none)\", AssetPreview.GetMiniTypeThumbnail(typeof(GameObject)));\n            } else if (!contentMap.TryGetValue(target, out content))\n            {\n                content = AssetFinderGUIContent.From(target.name, AssetPreview.GetMiniTypeThumbnail(target.GetType()));\n                contentMap.Add(target, content);\n            }\n\n            if (objectFieldStyle == null)\n            {\n                objectFieldStyle = new GUIStyle(EditorStyles.objectField)\n                {\n                    margin = new RectOffset(16, 0, 0, 0)\n                };\n            }\n\n            EditorGUIUtility.SetIconSize(new Vector2(12f, 12f));\n            GUI.Label(rect, content, objectFieldStyle);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderObjectDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bb7d43676aa6b92438f93faf242e93f1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSearchView.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderSearchView\n    {\n\n        public static GUIStyle toolbarSearchField;\n        public static GUIStyle toolbarSearchFieldCancelButton;\n        public static GUIStyle toolbarSearchFieldCancelButtonEmpty;\n        private bool caseSensitive;\n        private string searchTerm = string.Empty;\n\n        public static void InitSearchStyle()\n        {\n            toolbarSearchField = \"ToolbarSeachTextFieldPopup\";\n            toolbarSearchFieldCancelButton = \"ToolbarSeachCancelButton\";\n            toolbarSearchFieldCancelButtonEmpty = \"ToolbarSeachCancelButtonEmpty\";\n        }\n\n        public bool DrawLayout()\n        {\n            var dirty = false;\n\n            if (toolbarSearchField == null) InitSearchStyle();\n\n            GUILayout.BeginHorizontal(EditorStyles.toolbar);\n            {\n                bool v = GUILayout.Toggle(caseSensitive, \"Aa\", EditorStyles.toolbarButton, GUI2.GLW_24);\n                if (v != caseSensitive)\n                {\n                    caseSensitive = v;\n                    dirty = true;\n                }\n\n                GUILayout.Space(2f);\n                string value = GUILayout.TextField(searchTerm, toolbarSearchField, GUI2.GLW_140);\n                if (searchTerm != value)\n                {\n                    searchTerm = value;\n                    dirty = true;\n                }\n\n                GUIStyle style = string.IsNullOrEmpty(searchTerm)\n                    ? toolbarSearchFieldCancelButtonEmpty\n                    : toolbarSearchFieldCancelButton;\n                if (GUILayout.Button(\"Cancel\", style))\n                {\n                    searchTerm = string.Empty;\n                    dirty = true;\n                }\n            }\n            GUILayout.EndHorizontal();\n\n            return dirty;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSearchView.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2bdaf062f9e6ed74fa4901a9775036d0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSplitView.cs",
    "content": "//#define AssetFinderDEBUG\n\nusing System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n    internal class AssetFinderSplitView\n    {\n        private const float SPLIT_SIZE = 2f;\n\n\n        private readonly GUILayoutOption[] expandWH =\n        {\n            GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)\n        };\n\n\n        private readonly IWindow window;\n        private Rect _rect;\n\n        private int _visibleCount;\n        private bool dirty;\n\n        public bool isHorz;\n\n        private int resizeIndex = -1;\n        public bool hasResize;\n        public List<Info> splits = new List<Info>();\n\n        public AssetFinderSplitView(IWindow w)\n        {\n            window = w;\n        }\n\n        public bool isVisible => _visibleCount > 0;\n\n        public void CalculateWeight()\n        {\n            _visibleCount = 0;\n            var _totalWeight = 0f;\n\n            for (var i = 0; i < splits.Count; i++)\n            {\n                Info info = splits[i];\n                if (!info.visible) continue;\n\n                info.stIndex = _visibleCount;\n                _totalWeight += info.weight;\n\n                _visibleCount++;\n            }\n\n            if (_visibleCount == 0 || _totalWeight == 0)\n            {\n                Debug.LogWarning(\"Nothing visible!\");\n                return;\n            }\n\n            var cWeight = 0f;\n            for (var i = 0; i < splits.Count; i++)\n            {\n                Info info = splits[i];\n                if (!info.visible) continue;\n\n                cWeight += info.weight;\n                info.normWeight = info.weight / _totalWeight;\n            }\n        }\n\n        public void Draw(Rect rect)\n        {\n            if (rect.width > 0 || rect.height > 0) _rect = rect;\n\n            if (dirty)\n            {\n                dirty = false;\n                CalculateWeight();\n            }\n\n            if (resizeIndex == -1) ApplySizePolicies();\n\n            float sz = (_visibleCount - 1) * SPLIT_SIZE;\n            float dx = _rect.x;\n            float dy = _rect.y;\n\n            for (var i = 0; i < splits.Count; i++)\n            {\n                Info info = splits[i];\n                if (!info.visible) continue;\n\n                var rr = new Rect\n                (\n                    dx, dy,\n                    isHorz ? (_rect.width - sz) * info.normWeight : _rect.width,\n                    isHorz ? _rect.height : (_rect.height - sz) * info.normWeight\n                );\n\n                if ((rr.width > 0) && (rr.height > 0)) info.rect = rr;\n\n                if (info.draw != null) info.DoDraw();\n\n                if (info.sizePolicy == Info.SizePolicy.KeepPixel && Event.current.type == EventType.Repaint)\n                {\n                    float current = isHorz ? rr.width : rr.height;\n                    info.preferredPixel = Mathf.Max(info.minPixel, current);\n                }\n\n                if (info.stIndex < _visibleCount - 1) DrawSpliter(i, isHorz ? info.rect.xMax : info.rect.yMax);\n\n                if (isHorz)\n                {\n                    dx += info.rect.width + SPLIT_SIZE;\n                } else\n                {\n                    dy += info.rect.height + SPLIT_SIZE;\n                }\n            }\n        }\n\n        private void ApplySizePolicies()\n        {\n            int visible = 0;\n            for (int i = 0; i < splits.Count; i++) if (splits[i].visible) visible++;\n            if (visible == 0) return;\n\n            float totalGaps = (visible - 1) * SPLIT_SIZE;\n            float available = isHorz ? _rect.width : _rect.height;\n            float content = Mathf.Max(0f, available - totalGaps);\n\n            float fixedPixels = 0f;\n            float flexibleBasis = 0f;\n            for (int i = 0; i < splits.Count; i++)\n            {\n                var sp = splits[i];\n                if (!sp.visible) continue;\n                if (sp.sizePolicy == Info.SizePolicy.KeepPixel)\n                {\n                    float pref = sp.preferredPixel;\n                    pref = Mathf.Max(sp.minPixel, pref);\n                    fixedPixels += Mathf.Max(0f, pref);\n                }\n                else\n                {\n                    flexibleBasis += Mathf.Max(0.0001f, sp.weight);\n                }\n            }\n\n            float scale = 1f;\n            if (fixedPixels > content && fixedPixels > 0f) scale = content / fixedPixels;\n            float remaining = Mathf.Max(0f, content - Mathf.Min(fixedPixels, content));\n\n            for (int i = 0; i < splits.Count; i++)\n            {\n                var sp = splits[i];\n                if (!sp.visible) continue;\n                if (sp.sizePolicy == Info.SizePolicy.KeepPixel)\n                {\n                    float pref = sp.preferredPixel;\n                    pref = Mathf.Max(sp.minPixel, pref);\n                    sp.weight = Mathf.Max(0f, pref) * scale;\n                }\n            }\n\n            if (remaining > 0f)\n            {\n                float basis = Mathf.Max(0.0001f, flexibleBasis);\n                for (int i = 0; i < splits.Count; i++)\n                {\n                    var sp = splits[i];\n                    if (!sp.visible) continue;\n                    if (sp.sizePolicy == Info.SizePolicy.Flexible)\n                    {\n                        float share = Mathf.Max(0.0001f, sp.weight) / basis;\n                        sp.weight = remaining * share;\n                    }\n                }\n            }\n\n            CalculateWeight();\n        }\n\n        public void DrawLayout()\n        {\n            Rect rect = StartLayout(isHorz);\n            {\n                Draw(rect);\n            }\n            EndLayout(isHorz);\n        }\n\n\n        private void RefreshSpliterPos(int index, float px)\n        {\n\t\t\tInfo sp1 = splits[index];\n\t\t\tint rightIndex = -1;\n            for (int j = index + 1; j < splits.Count; j++)\n            {\n                if (splits[j].visible)\n                {\n                    rightIndex = j;\n                    break;\n                }\n            }\n            if (rightIndex < 0) return;\n\t\t\tInfo sp2 = splits[rightIndex];\n\n            Rect r1 = sp1.rect;\n            Rect r2 = sp2.rect;\n\n            float w1 = sp1.weight;\n            float w2 = sp2.weight;\n            float tt = w1 + w2;\n\n\t\t\tfloat dd = isHorz ? r2.xMax - r1.xMin - SPLIT_SIZE : r2.yMax - r1.yMin - SPLIT_SIZE;\n\t\t\tfloat m = isHorz ? Event.current.mousePosition.x - r1.x : Event.current.mousePosition.y - r1.y;\n\n\t\t\t// Enforce minimum pixel sizes for panels that prefer keeping pixel size\n\t\t\tfloat leftMin = 0f;\n\t\t\tfloat rightMin = 0f;\n\t\t\tif (sp1.sizePolicy == Info.SizePolicy.KeepPixel) leftMin = Mathf.Max(0f, sp1.minPixel);\n\t\t\tif (sp2.sizePolicy == Info.SizePolicy.KeepPixel) rightMin = Mathf.Max(0f, sp2.minPixel);\n\t\t\tfloat lower = Mathf.Min(dd - rightMin, leftMin);\n\t\t\tfloat upper = Mathf.Max(leftMin, dd - rightMin);\n\t\t\tm = Mathf.Clamp(m, lower, upper);\n            float pct = Mathf.Min(0.9f, Mathf.Max(0.1f, m / dd));\n\n            sp1.weight = tt * pct;\n            sp2.weight = tt * (1 - pct);\n\n            dirty = true;\n            if (window != null) window.WillRepaint = true;\n        }\n\n        private void DrawSpliter(int index, float px)\n        {\n            Rect dRect = _rect;\n\n            if (isHorz)\n            {\n                dRect.x = px;\n                dRect.width = SPLIT_SIZE;\n            } else\n            {\n                dRect.y = px;\n                dRect.height = SPLIT_SIZE;\n            }\n\n            if (Event.current.type == EventType.Repaint || Event.current.type == EventType.MouseMove) GUI2.Rect(dRect, Color.black, 0.4f);\n\n            var dRect2 = GUI2.Padding(dRect, -2f, -2f);\n            EditorGUIUtility.AddCursorRect(dRect2, isHorz ? MouseCursor.ResizeHorizontal : MouseCursor.ResizeVertical);\n            if ((Event.current.type == EventType.MouseDown) && dRect2.Contains(Event.current.mousePosition))\n            {\n                resizeIndex = index;\n                RefreshSpliterPos(index, px);\n                hasResize = true;\n            }\n\n            if (resizeIndex == index) RefreshSpliterPos(index, px);\n            if (Event.current.type == EventType.MouseUp)\n            {\n                resizeIndex = -1;\n                hasResize = false;\n            }\n        }\n\n        private Rect StartLayout(bool horz)\n        {\n            return horz\n                ? EditorGUILayout.BeginHorizontal(expandWH)\n                : EditorGUILayout.BeginVertical(expandWH);\n        }\n\n        private void EndLayout(bool horz)\n        {\n            if (horz)\n            {\n                EditorGUILayout.EndHorizontal();\n            } else\n            {\n                EditorGUILayout.EndVertical();\n            }\n        }\n\n        [Serializable]\n        internal class Info\n        {\n            public GUIContent title;\n            public Rect rect;\n            public float normWeight;\n            public int stIndex;\n\n            public bool visible = true;\n            public float weight = 1f;\n            public Action<Rect> draw;\n\n            public enum SizePolicy { Flexible, KeepPixel }\n            public SizePolicy sizePolicy = SizePolicy.Flexible;\n            public float preferredPixel = 200f;\n            public float minPixel = 50f;\n\n            // Dynamic title support\n            public Func<GUIContent> GetDynamicTitle;\n\n            // Drawer dirty state support\n            public Func<bool> GetDrawerDirtyState;\n            \n            // Refresh action support\n            public Action OnRefresh;\n\n            public void DoDraw()\n            {\n                Rect drawRect = rect;\n\n                // Use dynamic title if available, otherwise use static title\n                GUIContent baseTitle = GetDynamicTitle?.Invoke() ?? title;\n\n                if (baseTitle != null)\n                {\n                    var titleRect = new Rect(rect.x, rect.y, rect.width, 20f);\n                    GUI2.Rect(titleRect, Color.black, 0.2f);\n\n                    titleRect.xMin += 4f;\n\n                    // Check dirty state and modify title accordingly\n                    Color originalColor = GUI.contentColor;\n                    bool isDirty = GetDrawerDirtyState?.Invoke() ?? false;\n                    \n                    // Create title with asterisk if dirty\n                    string titleText = baseTitle.text;\n                    if (isDirty && !titleText.EndsWith(\"*\"))\n                    {\n                        titleText += \"*\";\n                        // Use theme-appropriate dirty indicator color instead of hardcoded yellow\n                        GUI.contentColor = EditorGUIUtility.isProSkin \n                            ? AssetFinderTheme.Dark.DirtyIndicator \n                            : AssetFinderTheme.Light.DirtyIndicator;\n                    }\n\n                    // Calculate available space for refresh button only if OnRefresh is available\n                    // Increased button width from 50f to 55f, adjusted status area accordingly\n                    float statusAreaWidth = OnRefresh != null ? (isDirty ? 205f : 55f) : 0f;\n                    \n                    // Draw main title\n                    var mainTitleRect = new Rect(titleRect.x, titleRect.y, titleRect.width - statusAreaWidth, titleRect.height);\n                    GUI.Label(mainTitleRect, new GUIContent(titleText, baseTitle.image, baseTitle.tooltip), EditorStyles.label);\n\n                    // Draw status message and refresh button only if OnRefresh is available\n                    if (OnRefresh != null)\n                    {\n                        if (isDirty)\n                        {\n                            // Status message - shorter text to fit\n                            var statusRect = new Rect(mainTitleRect.xMax + 5f, titleRect.y + 2f, 145f, titleRect.height);\n                            GUI.contentColor = new Color(0.7f, 0.7f, 0.7f, 0.8f); // Very dim color\n                            GUI.Label(statusRect, \"* possibly incomplete result\", EditorStyles.miniLabel);\n                        }\n                        \n                        GUI.contentColor = originalColor;\n                        // Increased refresh button width from 50f to 55f\n                        var refreshRect = new Rect(titleRect.xMax - 55f, titleRect.y + 1f, 53f, 14f);\n                        if (GUI.Button(refreshRect, \"Refresh\", EditorStyles.miniButtonRight))\n                        {\n                            OnRefresh.Invoke();\n                        }\n                    }\n                    \n                    GUI.contentColor = originalColor;\n                    drawRect.yMin += 20f;\n                }\n                draw(drawRect);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderSplitView.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dfa4ea84b5e859444a6fa014c2ef93a1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderTabView.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class DrawCallback\n    {\n        public Action<Rect> AfterDraw;\n        public Action<Rect> BeforeDraw;\n    }\n\n    internal class AssetFinderTabView\n    {\n        private readonly List<float> labelWidths = new List<float>();\n        public DrawCallback callback;\n        public bool canDeselectAll; // Can there be no active tabs\n        public int current;\n\n        public bool flexibleWidth = true;\n        public GUIContent[] labels;\n        private float labelTotalWidth;\n        public float offsetFirst;\n        public float offsetLast;\n        public Action onTabChange;\n        public float padding = 4f;\n\n        // Cached Rects for layout to avoid GC\n        private Rect toolbarRect;\n        public IWindow window;\n\n        public AssetFinderTabView(IWindow w, bool canDeselectAll)\n        {\n            window = w;\n            this.canDeselectAll = canDeselectAll;\n        }\n\n        public bool DrawLayout()\n        {\n            var result = false;\n\n            // Define the toolbar rect\n            GUIStyle style = EditorStyles.toolbarButton;\n\n            // Set up label rects if not already done\n            if (labelTotalWidth == 0 || labelWidths.Count != labels.Length)\n            {\n                labelTotalWidth = 0;\n                labelWidths.Clear();\n                for (var i = 0; i < labels.Length; i++)\n                {\n                    float w = style.CalcSize(labels[i]).x;\n                    labelWidths.Add(w);\n                    labelTotalWidth += w;\n                }\n            }\n\n            toolbarRect = GUILayoutUtility.GetRect(0, Screen.width, 20f, 20f);\n            GUI.Box(toolbarRect, GUIContent.none, EditorStyles.toolbar);\n            if (!flexibleWidth) toolbarRect.width = labelTotalWidth + labels.Length * padding;\n\n            // Call before draw action if available\n            callback?.BeforeDraw?.Invoke(toolbarRect);\n\n            // Draw each tab\n            Rect tabRect = toolbarRect;\n            tabRect.xMin += offsetFirst;\n            tabRect.xMax -= offsetLast;\n\n            // float ratio = flexibleWidth ? ((toolbarRect.width - offsetFirst - offsetLast) / labelTotalWidth) : 1;\n            float flexSpace = Mathf.Max(0, tabRect.width - labelTotalWidth) / labels.Length;\n            float pad = flexibleWidth ? flexSpace : padding;\n\n            for (var i = 0; i < labels.Length; i++)\n            {\n                bool isActive = i == current;\n                GUIContent lb = labels[i];\n\n                // Define the toggle rect\n                float w = labelWidths[i] + pad;\n                tabRect.width = w;\n\n                // Draw the toggle (or button) for the tab\n                bool clicked = lb.image != null\n                    ? GUI2.ToolbarToggle(ref isActive, lb.image, Vector2.zero, lb.tooltip, tabRect)\n                    : GUI2.Toggle(ref isActive, lb, EditorStyles.toolbarButton, tabRect);\n\n                tabRect.x += w;\n                if (!clicked)\n                {\n\n                    continue;\n                }\n\n                // Update the current tab and handle tab change logic\n                current = !isActive && canDeselectAll ? -1 : i;\n                result = true;\n\n                onTabChange?.Invoke();\n                if (window != null)\n                {\n                    // Tab changes only trigger repaint, NOT selection change\n                    window.WillRepaint = true;\n                }\n            }\n\n            // Call after draw action if available\n            callback?.AfterDraw?.Invoke(toolbarRect);\n            return result;\n        }\n\n        public static AssetFinderTabView FromEnum(Type enumType, IWindow w, bool canDeselectAll = false)\n        {\n            Array values = Enum.GetValues(enumType);\n            var labels = new List<GUIContent>();\n\n            foreach (object item in values)\n            {\n                labels.Add(AssetFinderGUIContent.FromString(item.ToString()));\n            }\n\n            return new AssetFinderTabView(w, canDeselectAll) { current = 0, labels = labels.ToArray() };\n        }\n\n        public static GUIContent GetGUIContent(object tex)\n        {\n            if (tex is GUIContent content) return content;\n            if (tex is Texture texture) return AssetFinderGUIContent.FromTexture(texture);\n            if (tex is string s) return AssetFinderGUIContent.FromString(s);\n            return GUIContent.none;\n        }\n\n        public static AssetFinderTabView Create(IWindow w, bool canDeselectAll = false, params object[] titles)\n        {\n            var labels = new List<GUIContent>();\n            foreach (object item in titles)\n            {\n                labels.Add(GetGUIContent(item));\n            }\n            return new AssetFinderTabView(w, canDeselectAll) { current = 0, labels = labels.ToArray() };\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderTabView.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e7d63b905dd16f547bdbbd0a004b7871\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderToggleList.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFinderToggleList\n    {\n\n        public int current;\n        public List<Info> listInfo = new List<Info>();\n\n        public AssetFinderToggleList AddInfo(GUIContent content, bool status, Action<bool> onChange, float w = 20f)\n        {\n            listInfo.Add(new Info\n            {\n                contentOn = content, contentOff = content, status = status, onChange = onChange, w = w\n            });\n            return this;\n        }\n\n        public AssetFinderToggleList AddInfo(GUIContent contentOn, GUIContent contentOff, Action<bool> onChange, float w = 20)\n        {\n            listInfo.Add(new Info\n            {\n                contentOn = contentOn, contentOff = contentOff, status = false, onChange = onChange, w = w\n            });\n            return this;\n        }\n        public AssetFinderToggleList AddInfo(GUIContent content, Action<bool> onChange, float w = 20)\n        {\n            listInfo.Add(new Info\n            {\n                contentOn = content, contentOff = content, status = false, onChange = onChange, w = w\n            });\n            return this;\n        }\n\n        public AssetFinderToggleList AddInfo(GUIContent content, float w = 20)\n        {\n            listInfo.Add(new Info\n            {\n                contentOn = content, contentOff = content, w = w\n            });\n            return this;\n        }\n\n        public void Draw(ref Rect rect)\n        {\n            if (Event.current.type == EventType.Layout) return;\n\n            for (var i = 0; i < listInfo.Count; i++)\n            {\n                Info info = listInfo[i];\n                rect.width = info.w;\n\n                if (GUI2.ToolbarToggle(rect, ref info.status, info.status ? info.contentOn : info.contentOff))\n                {\n                    info.onChange?.Invoke(info.status);\n                }\n\n                rect.x += info.w;\n            }\n        }\n\n        public void Draw(ref Rect rect, int index, ref bool b1)\n        {\n            if (Event.current.type == EventType.Layout) return;\n\n            Info info = listInfo[index];\n\n            rect.width = info.w;\n            if (GUI2.ToolbarToggle(rect, ref b1, b1 ? info.contentOn : info.contentOff))\n            {\n                if (info.onChange != null) info.onChange(info.status);\n            }\n            ;\n\n            // GUI.DrawTexture(rect, Texture2D.whiteTexture);\n            rect.x += info.w;\n        }\n        internal class Info\n        {\n            public GUIContent contentOff;\n            public GUIContent contentOn;\n            public Action<bool> onChange;\n            public bool status;\n            public float w;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/AssetFinderToggleList.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e9dfce69fdd06414bae56925dae0aa1e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Dark.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    partial class AssetFinderTheme\n    {\n        private static AssetFinderTheme CreateDarkTheme()\n        {\n            return new AssetFinderTheme\n            {\n                SelectionHighlight = new Color(0.2745f, 0.4902f, 0.7451f, 1f), // Unity's dark theme selection\n                SelectionHighlightInactive = new Color(0.3f, 0.3f, 0.3f, 1f),\n                ErrorColor = new Color(0.8235f, 0.1333f, 0.1333f, 1f),\n                WarningColor = new Color(0.9569f, 0.7373f, 0.0078f, 1f),\n                InfoColor = new Color(0.2980f, 0.4941f, 1.0f, 1f),\n                SuccessColor = new Color(0.0f, 0.8f, 0.0f, 1f),\n                SceneHighlight = new Color32(72, 150, 191, 255),\n                SeparatorLine = Color.black,\n                DirtyIndicator = new Color(1f, 0.9f, 0.4f, 1f)\n            };\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Dark.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e46df44b8004036419808d338f909aa3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Light.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    partial class AssetFinderTheme\n    {\n        private static AssetFinderTheme CreateLightTheme()\n        {\n            return new AssetFinderTheme\n            {\n                SelectionHighlight = new Color(0.2275f, 0.4471f, 0.6902f, 1f), // Unity's light theme selection\n                SelectionHighlightInactive = new Color(0.6824f, 0.6824f, 0.6824f, 1f),\n                ErrorColor = new Color(0.3529f, 0.0f, 0.0f, 1f),\n                WarningColor = new Color(0.2f, 0.2f, 0.0314f, 1f),\n                InfoColor = new Color(0.2980f, 0.4941f, 1.0f, 1f),\n                SuccessColor = new Color(0.0f, 0.8f, 0.0f, 1f),\n                SceneHighlight = Color.blue,\n                SeparatorLine = new Color(0.6f, 0.6f, 0.6f, 1f),\n                DirtyIndicator = new Color(0.8f, 0.7f, 0.2f, 1f)\n            };\n        }\n        \n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.Light.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d4e241366471be14f92379c7cfac41a8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderTheme\n    {\n        public static AssetFinderTheme Current => Dark;\n        public static AssetFinderTheme Dark { get; } = CreateDarkTheme();\n        public static AssetFinderTheme Light { get; } = CreateLightTheme();\n\n        private AssetFinderTheme()\n        {\n            InitializeLayoutOptions();\n        }\n\n        private void InitializeLayoutOptions()\n        {\n            ToolbarHeightOption = GUILayout.Height(ToolbarHeight);\n            CompactButtonHeight = GUILayout.Height(16f);\n            StandardButtonHeight = GUILayout.Height(18f);\n            ActionButtonHeight = GUILayout.Height(30f);\n            CancelButtonHeight = GUILayout.Height(25f);\n            WarningCloseButtonHeight = GUILayout.Height(38f);\n            CloseButtonWidth = GUILayout.Width(20f);\n            ToolbarButtonWidth = GUILayout.Width(24f);\n            IconButtonWidth = GUILayout.Width(IconButtonSize);\n            RefreshButtonWidth = GUILayout.Width(RefreshButtonSize);\n            ApplyButtonWidth = GUILayout.Width(100f);\n            TabPanelWidth = GUILayout.Width(160f);\n            RecursiveSearchLabelWidth = GUILayout.Width(100f);\n            ToggleWidth = GUILayout.Width(20f);\n            SelectionPanelWidth = GUILayout.Width(150f);\n            ViewModeSelectorWidth = GUILayout.Width(200f);\n            SettingsPanelHeight = GUILayout.Height(100f);\n            DropdownWidth = GUILayout.Width(320f);\n            LockButtonWidth = GUILayout.Width(150f);\n        }\n\n        // ============ METRICS ============\n        public readonly float ToolbarHeight = 30f;\n        public readonly float TreeItemHeight = 18f;\n        public readonly float TreeItemSpacing = 1f;\n        public readonly float TreeContentPadding = 2f;\n        public readonly float TreeIndentSize = 18f;\n        public readonly float TreeToggleSize = 16f;\n        public readonly float AssetIconSize = 16f;\n        public readonly float IconButtonSize = 24f;\n        public readonly float RefreshButtonSize = 18f;\n        public readonly float ScrollBarWidth = 18f;\n        public readonly float CompactSpacing = 4f;\n        public readonly float FooterButtonsOffset = 100f;\n        public readonly float TreeItemOffset = 18f;\n        public readonly float ViewModeSelectorWidthValue = 200f;\n\n        // ============ LAYOUT OPTIONS ============\n        public GUILayoutOption ToolbarHeightOption;\n        public GUILayoutOption CompactButtonHeight;\n        public GUILayoutOption StandardButtonHeight;\n        public GUILayoutOption ActionButtonHeight;\n        public GUILayoutOption CancelButtonHeight;\n        public GUILayoutOption WarningCloseButtonHeight;\n        public GUILayoutOption CloseButtonWidth;\n        public GUILayoutOption ToolbarButtonWidth;\n        public GUILayoutOption IconButtonWidth;\n        public GUILayoutOption RefreshButtonWidth;\n        public GUILayoutOption ApplyButtonWidth;\n        public GUILayoutOption TabPanelWidth;\n        public GUILayoutOption RecursiveSearchLabelWidth;\n        public GUILayoutOption ToggleWidth;\n        public GUILayoutOption SelectionPanelWidth;\n        public GUILayoutOption ViewModeSelectorWidth;\n        public GUILayoutOption SettingsPanelHeight;\n        public GUILayoutOption DropdownWidth;\n        public GUILayoutOption LockButtonWidth;\n\n        // ============ COLORS ============\n        public Color SelectionHighlight;\n        public Color SelectionHighlightInactive;\n        public Color ErrorColor;\n        public Color WarningColor;\n        public Color InfoColor;\n        public Color SuccessColor;\n        public Color SceneHighlight;\n        public Color SeparatorLine;\n        public Color DirtyIndicator;\n        \n        public Rect GetProgressBarRect()\n        {\n            return GUILayoutUtility.GetRect(1f, Screen.width, 18f, 18f);\n        }\n\n        public Rect GetRefreshButtonRect(Rect parentRect)\n        {\n            return new Rect(parentRect.xMax - AssetIconSize, parentRect.yMin - 14f, RefreshButtonSize, RefreshButtonSize);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme/AssetFinderTheme.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 707044acb1e550544b801b9f78ac858a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI/Theme.meta",
    "content": "fileFormatVersion: 2\nguid: 3c2cd070a17045d98ec4a456b160665e\ntimeCreated: 1753869076"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/UI.meta",
    "content": "fileFormatVersion: 2\nguid: ecd25f71eac2146a58139581a59c8ad1\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.CacheManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        protected void DrawScanProject()\n        {\n            bool writeImportLog = settings.writeImportLog;\n            settings.writeImportLog = EditorGUILayout.Toggle(\"Write Import Log\", settings.writeImportLog);\n            if (writeImportLog != settings.writeImportLog)\n            {\n                EditorUtility.SetDirty(this);\n            }\n\n            if (GUILayout.Button(\"Scan project\"))\n            {\n                AssetFinderAsset.shouldWriteImportLog = writeImportLog;\n                AssetFinderCache.DeleteCache();\n                AssetFinderCache.CreateCache();\n            }\n        }\n        \n        protected bool CheckDrawImport()\n        {\n            AssetFinderUnity.RefreshEditorStatus();\n            \n            if (AssetFinderUnity.isEditorCompiling)\n            {\n                EditorGUILayout.HelpBox(\"Compiling scripts, please wait!\", MessageType.Warning);\n                Repaint();\n                return false;\n            }\n\n            if (AssetFinderUnity.isEditorUpdating)\n            {\n                EditorGUILayout.HelpBox(\"Importing assets, please wait!\", MessageType.Warning);\n                Repaint();\n                return false;\n            }\n\n            InitIfNeeded();\n\n            if (EditorSettings.serializationMode != SerializationMode.ForceText)\n            {\n                EditorGUILayout.HelpBox(\"FR2 requires serialization mode set to FORCE TEXT!\", MessageType.Warning);\n                if (GUILayout.Button(\"FORCE TEXT\")) EditorSettings.serializationMode = SerializationMode.ForceText;\n\n                return false;\n            }\n\n            if (AssetFinderCache.hasCache && !AssetFinderCache.CheckSameVersion())\n            {\n                EditorGUILayout.HelpBox(\"Incompatible cache version found!!!\\nFR2 will need a full refresh and according to your project's size this process may take several minutes to complete finish!\",\n                    MessageType.Warning);\n\n                DrawScanProject();\n                return false;\n            }\n\n            if (AssetFinderCache.isReady) return DrawEnable();\n\n            if (!AssetFinderCache.hasCache)\n            {\n                EditorGUILayout.HelpBox(\n                    \"FR2 cache not found!\\nA first scan is needed to build the cache for all asset references.\\nDepending on the size of your project, this process may take a few minutes to complete but once finished, searching for asset references will be incredibly fast!\",\n                    MessageType.Warning);\n\n                DrawScanProject();\n                return false;\n            }\n\n            if (!DrawEnable()) return false;\n\n            AssetFinderCache api = AssetFinderCache.Api;\n            if (api.workCount > 0)\n            {\n                string text = \"Refreshing ... \" + (int)(api.progress * api.workCount) + \" / \" + api.workCount;\n\n                // Show current asset being processed\n                if (!string.IsNullOrEmpty(api.currentAssetName))\n                {\n                    EditorGUILayout.LabelField(api.currentAssetName, EditorStyles.miniLabel);\n                }\n\n                Rect rect = GUILayoutUtility.GetRect(1f, Screen.width, 18f, 18f);\n                EditorGUI.ProgressBar(rect, api.progress, text);\n                Repaint();\n            } \n            else\n            {\n                api.workCount = 0;\n                api.ready = true;\n            }\n\n            return false;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.CacheManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1c11665c77d8bb74b89a3b61ef10a1be\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Drawing.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        private void DrawScenePanel(Rect rect)\n        {\n            AssetFinderRefDrawer drawer = isFocusingUses\n                ? IsSelectingAssets ? null : SceneUsesDrawer\n                : IsSelectingAssets ? RefInScene : RefSceneInScene;\n            \n            if (drawer == null) return;\n\n            if (!AssetFinderSceneCache.isReady && AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning)\n            {\n                DrawSceneCacheProgress(rect);\n                rect.yMin += 18f;\n            }\n            \n            if (AssetFinderSceneCache.hasCache) drawer.Draw(rect);\n        }\n\n        private void DrawSceneCacheProgress(Rect rect)\n        {\n            Rect rr = rect;\n            rr.height = 16f;\n\n            if (AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning)\n            {\n                int cur = AssetFinderSceneCache.Api.current, total = AssetFinderSceneCache.Api.total;\n                var progress = Mathf.Clamp01(cur * 1f / total);\n                var progressText = AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning\n                    ? $\"Scanning objects: {cur} / {total}\"\n                    : $\"{cur} / {total}\";\n                EditorGUI.ProgressBar(rr, progress, progressText);\n\n                if (cur >= total)\n                {\n                    AssetFinderLOG.LogWarning($\"Stuck at scanning? {cur}/{total}\");\n                }\n                WillRepaint = true;\n                return;\n            }\n            \n            string statusText;\n            switch (AssetFinderSceneCache.Api.Status)\n            {\n                case SceneCacheStatus.None:\n                    statusText = \"Scene cache is not ready!\";\n                    break;\n                case SceneCacheStatus.Changed:\n                    statusText = \"Scene changed - results might be incompleted\";\n                    break;\n                case SceneCacheStatus.Scanning:\n                    statusText = \"Preparing to scan scene objects...\";\n                    break;\n                case SceneCacheStatus.Ready:\n                    statusText = \"Scene cache ready\";\n                    break;\n                default:\n                    statusText = \"Unknown status\";\n                    break;\n            }\n            \n            EditorGUI.ProgressBar(rr, 0f, statusText);\n        }\n\n\n\n        private void DrawAssetPanel(Rect rect)\n        {\n            AssetFinderRefDrawer drawer = GetAssetDrawer();\n            if (drawer == null) return;\n            drawer.Draw(rect);\n\n            if (!drawer.showDetail) return;\n\n            settings.details = true;\n            drawer.showDetail = false;\n            sp1.splits[2].visible = settings.details;\n            sp1.CalculateWeight();\n            Repaint();\n        }\n\n        private void DrawGitWarningPanel()\n        {\n            if (!AssetFinderSettingExt.isGitProject || AssetFinderSettingExt.gitIgnoreAdded || AssetFinderSettingExt.hideGitIgnoreWarning) return;\n            \n            EditorGUILayout.BeginHorizontal();\n            \n            // Left side: Warning message\n            EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true));\n            EditorGUILayout.HelpBox(\"You should add **/AssetFinderCache.asset* to your .gitignore file to avoid committing cache files.\", MessageType.Warning);\n            EditorGUILayout.EndVertical();\n            \n            // Right side: Buttons stacked vertically\n            EditorGUILayout.BeginVertical(AssetFinderTheme.Current.ApplyButtonWidth);\n\n            if (GUILayout.Button(\"Apply\", AssetFinderTheme.Current.CompactButtonHeight))\n            {\n                AssetFinderGitUtil.AddFR2CacheToGitIgnore();\n                AssetFinderSettingExt.gitIgnoreAdded = true;\n            }\n\n            if (GUILayout.Button(\"Ignore\", AssetFinderTheme.Current.CompactButtonHeight))\n            {\n                AssetFinderSettingExt.hideGitIgnoreWarning = true;\n            }\n            \n            EditorGUILayout.EndVertical();\n            \n            EditorGUILayout.EndHorizontal();\n        }\n\n        private void DrawToolsWarningPanel()\n        {\n            if (AssetFinderSettingExt.hideToolsWarning) return;\n            \n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.HelpBox(AssetFinderGUIContent.From(\"Tools are POWERFUL & DANGEROUS! Only use if you know what you are doing!!!\", AssetFinderIcon.Warning.image));\n            if (GUILayout.Button(\"  x\", EditorStyles.label, AssetFinderTheme.Current.CloseButtonWidth, AssetFinderTheme.Current.WarningCloseButtonHeight))\n            {\n                AssetFinderSettingExt.hideToolsWarning = true;\n            }\n            EditorGUILayout.EndHorizontal();\n        }\n\n\n        internal bool DrawButton(Rect rect, ref bool show, GUIContent icon)\n        {\n            var changed = false;\n            Color oColor = GUI.color;\n            Color originalContentColor = GUI.contentColor;\n            \n            // For light theme, make icons more visible by adjusting content color\n            if (!EditorGUIUtility.isProSkin)\n            {\n                GUI.contentColor = new Color(0.3f, 0.3f, 0.3f, 1f); // Darker color for better visibility in light theme\n            }\n            \n            if (show) GUI.color = new Color(0.7f, 1f, 0.7f, 1f);\n            {\n                if (GUI.Button(rect, icon, EditorStyles.toolbarButton))\n                {\n                    show = !show;\n                    EditorUtility.SetDirty(this);\n                    WillRepaint = true;\n                    changed = true;\n                }\n            }\n            GUI.color = oColor;\n            GUI.contentColor = originalContentColor;\n            return changed;\n        }\n\n        internal void DrawAssetViewSettings()\n        {\n            bool isDisable = !sp2.splits[1].visible;\n            EditorGUI.BeginDisabledGroup(isDisable);\n            {\n                GUI2.ToolbarToggle(ref AssetFinderSetting.s.displayAssetBundleName, AssetFinderIcon.AssetBundle.image, Vector2.zero, \"Show / Hide Assetbundle Names\");\n#if UNITY_2017_1_OR_NEWER\n                GUI2.ToolbarToggle(ref AssetFinderSetting.s.displayAtlasName, AssetFinderIcon.Atlas.image, Vector2.zero, \"Show / Hide Atlas packing tags\");\n#endif\n                GUI2.ToolbarToggle(ref AssetFinderSetting.s.showUsedByClassed, AssetFinderIcon.Material.image, Vector2.zero, \"Show / Hide usage icons\");\n\n                if (GUILayout.Button(\"CSV\", EditorStyles.toolbarButton)) OnCSVClickExtension();\n            }\n            EditorGUI.EndDisabledGroup();\n        }\n\n        private AssetFinderEnumDrawer groupModeED;\n        private AssetFinderEnumDrawer toolModeED;\n        private AssetFinderEnumDrawer sortModeED;\n\n        internal void DrawViewModes(Rect rect)\n        {\n            var (rect1, rect2) = rect.HzSplit(0f, 0.5f);\n\n            if (toolModeED == null)\n            {\n                toolModeED = new AssetFinderEnumDrawer\n                {\n                    AssetFinderenum = new AssetFinderEnumDrawer.EnumInfo(\n                        AssetFinderRefDrawer.Mode.Type,\n                        AssetFinderRefDrawer.Mode.Folder,\n                        AssetFinderRefDrawer.Mode.Extension\n                    )\n                };\n            }\n            if (groupModeED == null) groupModeED = new AssetFinderEnumDrawer { tooltip = \"Group By\" };\n            if (sortModeED == null) sortModeED = new AssetFinderEnumDrawer { tooltip = \"Sort By\" };\n\n            if (settings.toolMode)\n            {\n                AssetFinderRefDrawer.Mode tMode = settings.toolGroupMode;\n                if (toolModeED.Draw(rect1, ref tMode))\n                {\n                    settings.toolGroupMode = tMode;\n                    MarkDirty();\n                    RefreshSort();\n                }\n            } else\n            {\n                AssetFinderRefDrawer.Mode gMode = settings.groupMode;\n                if (groupModeED.Draw(rect1, ref gMode))\n                {\n                    settings.groupMode = gMode;\n                    MarkDirty();\n                    RefreshSort();\n                }\n            }\n\n            AssetFinderRefDrawer.Sort sMode = settings.sortMode;\n            if (sortModeED.Draw(rect2, ref sMode))\n            {\n                settings.sortMode = sMode;\n                RefreshSort();\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Drawing.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ed565692c3c6a724fb0f4e66603f1662\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.GuidManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        private Dictionary<string, UnityObject> guidObjs;\n        private Vector2 scrollPos;\n        private string tempGUID;\n        private string tempFileID;\n        private UnityObject tempObject;\n\n        private void DrawGUIDs()\n        {\n            GUILayout.Label(\"GUID to Object\", EditorStyles.boldLabel);\n            GUILayout.BeginHorizontal();\n            {\n                string guid = EditorGUILayout.TextField(tempGUID ?? string.Empty);\n                string fileId = EditorGUILayout.TextField(tempFileID ?? string.Empty);\n                EditorGUILayout.ObjectField(tempObject, typeof(UnityObject), false, GUI2.GLW_160);\n\n                if (GUILayout.Button(\"Paste\", EditorStyles.miniButton, GUI2.GLW_70))\n                {\n                    string[] split = EditorGUIUtility.systemCopyBuffer.Split('/');\n                    guid = split[0];\n                    fileId = split.Length == 2 ? split[1] : string.Empty;\n                }\n\n                if ((guid != tempGUID || fileId != tempFileID) && !string.IsNullOrEmpty(guid))\n                {\n                    tempGUID = guid;\n                    tempFileID = fileId;\n                    string fullId = string.IsNullOrEmpty(fileId) ? tempGUID : tempGUID + \"/\" + tempFileID;\n\n                    tempObject = AssetFinderUnity.LoadAssetAtPath<UnityObject>\n                    (\n                        AssetDatabase.GUIDToAssetPath(fullId)\n                    );\n                }\n\n                if (GUILayout.Button(\"Set FileID\"))\n                {\n                    var newDict = new Dictionary<string, UnityObject>();\n                    foreach (KeyValuePair<string, UnityObject> kvp in guidObjs)\n                    {\n                        string key = kvp.Key.Split('/')[0];\n                        if (!string.IsNullOrEmpty(fileId)) key = key + \"/\" + fileId;\n\n                        var value = AssetFinderUnity.LoadAssetAtPath<UnityObject>\n                        (\n                            AssetDatabase.GUIDToAssetPath(key)\n                        );\n                        newDict.Add(key, value);\n                    }\n\n                    guidObjs = newDict;\n                }\n            }\n            GUILayout.EndHorizontal();\n            GUILayout.Space(10f);\n            if (guidObjs == null)\n            {\n                GUILayout.FlexibleSpace();\n                return;\n            }\n\n            scrollPos = GUILayout.BeginScrollView(scrollPos);\n            {\n                foreach (KeyValuePair<string, UnityObject> item in guidObjs)\n                {\n                    GUILayout.BeginHorizontal();\n                    {\n                        UnityObject obj = item.Value;\n\n                        EditorGUILayout.ObjectField(obj, typeof(UnityObject), false, GUI2.GLW_150);\n                        string idi = item.Key;\n                        GUILayout.TextField(idi, GUI2.GLW_320);\n                        if (GUILayout.Button(AssetFinderGUIContent.FromString(\"Copy\"), EditorStyles.miniButton, GUI2.GLW_50))\n                        {\n                            tempObject = obj;\n\n                            string[] arr = item.Key.Split('/');\n                            tempGUID = arr[0];\n                            tempFileID = arr[1];\n                        }\n\n                    }\n                    GUILayout.EndHorizontal();\n                }\n            }\n            GUILayout.EndScrollView();\n\n            GUILayout.BeginHorizontal();\n            if (GUILayout.Button(\"Merge Selection To\"))\n            {\n                string fullId = string.IsNullOrEmpty(tempFileID) ? tempGUID : tempGUID + \"/\" + tempFileID;\n                AssetFinderExport.MergeDuplicate(fullId);\n            }\n\n            EditorGUILayout.ObjectField(tempObject, typeof(UnityObject), false, GUI2.GLW_120);\n            GUILayout.EndHorizontal();\n            GUILayout.FlexibleSpace();\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.GuidManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a0b54e82f6de36e489536582ac285f6c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Initialization.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        private void InitializeComponents()\n        {\n            \n            // Initialize UI components first to ensure selection exists before selection manager events\n            InitializeUIComponents();\n            InitializeNavigationHistory();\n            InitializeDrawers();\n            InitializeTools();\n            InitializeDrawerProperties();\n            \n            InitTabs();\n            InitPanes();\n            \n            // Initialize selection manager AFTER everything else is ready\n            InitializeSelectionManager();\n            \n            if (AssetFinderCache.isReady)\n            {\n                RefreshActiveTab();\n                RefreshFR2View();\n            }\n            else\n            {\n                // Debug.LogWarning(\"FR2 is not Ready just yet!\");    \n                AssetFinderCache.onReady -= RefreshActiveTab;\n                AssetFinderCache.onReady += RefreshActiveTab;\n                AssetFinderCache.onReady -= RefreshFR2View;\n                AssetFinderCache.onReady += RefreshFR2View;\n            }\n            \n            Repaint();\n        }\n\n        void RefreshActiveTab()\n        {\n            AssetFinderCache.onReady -= RefreshActiveTab;\n            AssetFinderCache.onReady -= RefreshFR2View;\n            \n            // If tabs are not initialized yet, we'll defer this call\n            // OnGUI2 will handle calling tab changes when tabs are initialized\n            if (tabs == null || toolTabs == null)\n            {\n                return;\n            }\n            \n            if (settings.toolMode)\n            {\n                toolTabs.onTabChange?.Invoke();\n            }\n            else\n            {\n                tabs.onTabChange?.Invoke();\n            }\n            \n            // If selection was out of sync due to cache not being ready, sync now\n            if (isSelectionOutOfSync && selection != null && !selection.isLock)\n            {\n                selection.SyncFromGlobalSelection();\n                RefreshFR2View();\n                isSelectionOutOfSync = false;\n            }\n        }\n        \n\n        private void InitializeNavigationHistory()\n        {\n            if (navigationHistory == null) navigationHistory = new AssetFinderNavigationHistory();\n            navigationHistory.SetWindow(this);\n        }\n\n        private void InitializeSelectionManager()\n        {\n            AssetFinderSelectionManager.SelectionChanged -= OnSelectionManagerChanged;\n            AssetFinderSelectionManager.SelectionChanged += OnSelectionManagerChanged;\n        }\n\n        private void InitializeDrawers()\n        {\n            UsesDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.groupMode,\n                showFullPath = settings.showFullPath,\n                showFileSize = settings.showFileSize,\n                showExtension = settings.showFileExtension,\n                showUsageType = settings.showUsageType,\n                showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName,\n                showAtlasName = AssetFinderSetting.s.displayAtlasName,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => true,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"[Selected Assets] are not [USING] (depends on / contains reference to) any other assets!\",\n                GetContextualEmptyMessage = () => cachedUsesMessage\n            };\n\n            UsedByDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.groupMode,\n                showFullPath = settings.showFullPath,\n                showFileSize = settings.showFileSize,\n                showExtension = settings.showFileExtension,\n                showUsageType = settings.showUsageType,\n                showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName,\n                showAtlasName = AssetFinderSetting.s.displayAtlasName,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => !isFocusingUsedBy,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"[Selected Assets] are not [USED BY] any other assets!\",\n                GetContextualEmptyMessage = () => cachedUsedByMessage\n            };\n\n            AddressableDrawer = new AssetFinderAddressableDrawer(this, () => settings.sortMode, () => settings.groupMode);\n\n            Duplicated = new AssetFinderDuplicateTree2(this, () => settings.sortMode, () => settings.toolGroupMode);\n\n            RefInScene = new AssetFinderRefDrawer(new AssetFinderRefDrawer.SceneDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.groupMode,\n                showFullPath = settings.showFullPath,\n                showDetails = true,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => true,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"[Selected Assets] are not [USED BY] any GameObjects in current scene!\",\n                GetContextualEmptyMessage = () => cachedRefInSceneMessage\n            };\n\n            RefSceneInScene = new AssetFinderRefDrawer(new AssetFinderRefDrawer.SceneDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.groupMode,\n                showFullPath = settings.showFullPath,\n                showDetails = true,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => true,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"[Selected GameObjects] are not [USED BY] any GameObjects in current scene!\",\n                GetContextualEmptyMessage = () => cachedSceneInSceneMessage\n            };\n\n            SceneUsesDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.SceneDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.groupMode,\n                showFullPath = settings.showFullPath,\n                showDetails = true,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => true,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"[Selected GameObjects] are not [USING] any GameObjects in current scene!\",\n                GetContextualEmptyMessage = () => cachedSceneUsesMessage\n            };\n\n            SceneToAssetDrawer = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.groupMode,\n                showFullPath = settings.showFullPath,\n                showFileSize = settings.showFileSize,\n                showExtension = settings.showFileExtension,\n                showUsageType = settings.showUsageType,\n                showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName,\n                showAtlasName = AssetFinderSetting.s.displayAtlasName,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => true,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"[Selected GameObjects] are not [USING] any assets!\",\n                GetContextualEmptyMessage = () => cachedSceneToAssetMessage\n            };\n\n            RefUnUse = new AssetFinderRefDrawer(new AssetFinderRefDrawer.AssetDrawingConfig\n            {\n                window = this,\n                getSortMode = () => settings.sortMode,\n                getGroupMode = () => settings.toolGroupMode,\n                showFullPath = settings.showFullPath,\n                showFileSize = settings.showFileSize,\n                showExtension = settings.showFileExtension,\n                showUsageType = settings.showUsageType,\n                showAssetBundleName = AssetFinderSetting.s.displayAssetBundleName,\n                showAtlasName = AssetFinderSetting.s.displayAtlasName,\n                showToggle = true,\n                shouldShowExtension = () => settings.showFileExtension,\n                shouldShowDetailButton = () => !isFocusingUnused,\n                onCacheInvalidated = () => { }\n            })\n            {\n                messageEmpty = \"Wow! No unused assets found!\",\n                // RefUnUse doesn't need contextual messages as it's not selection-dependent\n            };\n        }\n\n        private void InitializeTools()\n        {\n            UsedInBuild = new AssetFinderUsedInBuild(this, () => settings.sortMode, () => settings.toolGroupMode);\n            MissingReference = new AssetFinderMissingReference(this, () => settings.sortMode, () => settings.toolGroupMode);\n            AssetOrganizer = new AssetFinderAssetOrganizer(this, () => settings.sortMode, () => settings.toolGroupMode);\n            DeleteEmptyFolder = new AssetFinderDeleteEmptyFolder(this, () => settings.sortMode, () => settings.toolGroupMode);\n        }\n\n        private void InitializeUIComponents()\n        {\n            selection = new AssetFinderSelection(this, () => settings.sortMode, () => settings.groupMode);\n            selection.OnSelectionChanged -= OnLocalSelectionChanged;\n            selection.OnSelectionChanged += OnLocalSelectionChanged;\n            bookmark = new AssetFinderBookmark(this, () => settings.sortMode, () => settings.groupMode);\n            \n            // Setup bookmark cache invalidation callback - each drawer will invalidate its own cache\n            AssetFinderBookmark.OnBookmarkChanged = () => {\n                UsesDrawer?.InvalidateGroupCache();\n                UsedByDrawer?.InvalidateGroupCache();\n                RefUnUse?.InvalidateGroupCache();\n                RefInScene?.InvalidateGroupCache();\n                SceneToAssetDrawer?.InvalidateGroupCache();\n                SceneUsesDrawer?.InvalidateGroupCache();\n                RefSceneInScene?.InvalidateGroupCache();\n            };\n            \n            // Initial sync with Unity selection - sync immediately if cache is ready\n            if (AssetFinderCache.isReady && selection != null)\n            {\n                selection.SyncFromGlobalSelection();\n                isSelectionOutOfSync = false;\n            }\n            else\n            {\n                // Defer sync until cache is ready\n                EditorApplication.delayCall += () =>\n                {\n                    if (selection == null) return;\n                    if (!AssetFinderCache.isReady) return;\n                    \n                    selection.SyncFromGlobalSelection();\n                    isSelectionOutOfSync = false;\n                    RefreshFR2View();\n                };\n            }\n        }\n\n        private void OnLocalSelectionChanged()\n        {\n            // When local selection changes (user interacts with selection panel), \n            // refresh the Uses/Used By tabs to reflect the current selection\n            if (selection != null)\n            {\n                // Debug.Log($\"OnLocalSelectionChanged - Count: {selection.Count}, IsSelectingAsset: {selection.isSelectingAsset}, GuidCount: {selection.guidSet.Count}\");\n                RefreshFR2View();\n            }\n        }\n\n        private void InitializeDrawerProperties()\n        {\n            this.CacheAllDrawers();\n            this.RefreshShowFileExtension();\n            this.RefreshShowFullPath();\n            this.RefreshShowFileSize();\n            this.RefreshShowUsageType();\n        }\n\n        private void InitPanes()\n        {\n            sp2 = new AssetFinderSplitView(this)\n            {\n                isHorz = false,\n                splits = new List<AssetFinderSplitView.Info>\n                {\n                    new AssetFinderSplitView.Info\n                    {\n                        title = new GUIContent(\"Scene\", AssetFinderIcon.Scene.image),\n                        draw = DrawScene,\n                        visible = settings.scene,\n                        GetDynamicTitle = GetScenePanelTitle,\n                        GetDrawerDirtyState = IsScenePanelDirty,\n                        OnRefresh = () => AssetFinderSceneCache.Api.ForceRefresh()\n                    },\n                    new AssetFinderSplitView.Info\n                    {\n                        title = new GUIContent(\"Assets\", AssetFinderIcon.Asset.image),\n                        draw = DrawAsset,\n                        visible = settings.asset,\n                        GetDynamicTitle = GetAssetPanelTitle,\n                        GetDrawerDirtyState = IsAssetPanelDirty,\n                        OnRefresh = () => AssetFinderCache.Api.IncrementalRefresh()\n                    },\n                    new AssetFinderSplitView.Info\n                        { title = null, draw = rect => AddressableDrawer.Draw(rect), visible = false }\n                }\n            };\n\n            sp2.CalculateWeight();\n\n            sp1 = new AssetFinderSplitView(this)\n            {\n                isHorz = true,\n                splits = new List<AssetFinderSplitView.Info>\n                {\n                    new AssetFinderSplitView.Info\n                    {\n                        title = null, //new GUIContent(\"Selection\"),\n                        draw = DrawSelectionPanel,\n                        weight = 0f,\n                        visible = settings.selection,\n                        sizePolicy = AssetFinderSplitView.Info.SizePolicy.KeepPixel,\n                        preferredPixel = settings.selectionPanelPixel\n                    },\n                    new AssetFinderSplitView.Info\n                    {\n                        title = null,\n                        draw = _ => sp2.Draw(_),\n                        weight = 1f,\n                        visible = true,\n                        sizePolicy = AssetFinderSplitView.Info.SizePolicy.Flexible\n                    },\n                    new AssetFinderSplitView.Info\n                    {\n                        title = new GUIContent(\"Details\", AssetFinderIcon.Hierarchy.image),\n                        draw = DrawDetailsPanel,\n                        weight = 0f,\n                        visible = settings.details,\n                        sizePolicy = AssetFinderSplitView.Info.SizePolicy.KeepPixel,\n                        preferredPixel = settings.detailsPanelPixel\n                    },\n                    new AssetFinderSplitView.Info\n                    {\n                        title = new GUIContent(\"Bookmark\", AssetFinderIcon.Favorite.image),\n                        draw = _ => bookmark.Draw(_),\n                        weight = 0f,\n                        visible = settings.bookmark,\n                        sizePolicy = AssetFinderSplitView.Info.SizePolicy.KeepPixel,\n                        preferredPixel = settings.bookmarkPanelPixel\n                    }\n                }\n            };\n\n            sp1.CalculateWeight();\n        }\n\n        private void InitTabs()\n        {\n            bottomTabs = AssetFinderTabView.Create(this, true,\n                new GUIContent(AssetFinderIcon.Setting.image, \"Settings\"),\n                new GUIContent(AssetFinderIcon.Ignore.image, \"Ignore\"),\n                new GUIContent(AssetFinderIcon.Filter.image, \"Filter by Type\")\n            );\n            bottomTabs.current = -1;\n            bottomTabs.flexibleWidth = false;\n            bottomTabs.onTabChange = () => { \n                // Bottom tab changes work directly on FR2 selection - no locks needed\n            };\n\n            toolTabs = AssetFinderTabView.Create(this, false, \"Duplicate\", \"GUID\", \"Unused\", \"In Build\", \"Others\");\n            toolTabs.current = settings.toolTabIndex;\n            toolTabs.onTabChange = () =>\n            {\n                settings.toolTabIndex = toolTabs.current;\n\n                if (toolTabs.current == 0) // Duplicate\n                {\n                    if (Duplicated != null)\n                    {\n                        Duplicated.SetDirty();\n                        Duplicated.RefreshSort();\n                    }\n                }\n\n                if (toolTabs.current == 1) // GUID\n                {\n                    // GUIDs tool doesn't use drawer system, no action needed\n                }\n\n                if (toolTabs.current == 2) // Unused\n                {\n                    if (RefUnUse != null)\n                    {\n                        RefUnUse.ResetUnusedAsset(settings.recursiveUnusedScan);\n                        RefUnUse.SetDirty();\n                        RefUnUse.RefreshSort();\n                    }\n                }\n\n                if (toolTabs.current == 3) // UsedInBuild\n                {\n                    if (UsedInBuild != null)\n                    {\n                        UsedInBuild.SetDirty();\n                        UsedInBuild.RefreshSort();\n                    }\n                }\n\n                if (toolTabs.current == 4) // Others\n                {\n                    // Others tab has its own internal tab system, no action needed\n                }\n                \n                // Ensure proper group mode restrictions for tools that need them\n                if (toolTabs.IsFocusingAny(2, 3)) // Unused or UsedInBuild\n                {\n                    if (!allowedModes.Contains(settings.toolGroupMode))\n                    {\n                        settings.toolGroupMode = AssetFinderRefDrawer.Mode.Type;\n                    }\n                }\n                \n                Repaint();\n            };\n            \n            if (AssetFinderAddressable.asmStatus == AssetFinderAddressable.ASMStatus.AsmNotFound)\n            { // No Addressable\n                tabs = AssetFinderTabView.Create(this, false, // , \"Tools\"\n                    \"Uses\", \"Used By\"\n                );\n            } else\n            {\n                tabs = AssetFinderTabView.Create(this, false, // , \"Tools\"\n                    \"Uses\", \"Used By\", \"Addressables\"\n                );\n            }\n            \n            tabs.onTabChange = () =>\n            {\n                settings.mainTabIndex = tabs.current;\n                OnTabChange();\n            };\n            tabs.current = settings.mainTabIndex;\n            \n            const float IconW = 24f;\n            const float LockButtonW = 150f; // Fixed width for lock button with text\n            const float BookmarkW = 44f;\n            tabs.offsetFirst = IconW * 2 + LockButtonW; // prev, next, lock(with text)\n            tabs.offsetLast = IconW * 3 + BookmarkW;\n\n            tabs.callback = new DrawCallback\n            {\n                BeforeDraw = rect =>\n                {\n                    if (navigationHistory == null) navigationHistory = new AssetFinderNavigationHistory();\n                    \n                    rect.width = IconW;\n                    \n                    // Previous button\n                    bool canGoBack = navigationHistory.CanGoBack;\n                    EditorGUI.BeginDisabledGroup(!canGoBack);\n                    if (GUI.Button(rect, \"<\", EditorStyles.toolbarButton))\n                    {\n                        navigationHistory.GoBack();\n                        GUIUtility.ExitGUI(); // Prevent layout errors\n                    }\n                    EditorGUI.EndDisabledGroup();\n                    rect.x += IconW;\n                    \n                    // Next button  \n                    bool canGoForward = navigationHistory.CanGoForward;\n                    EditorGUI.BeginDisabledGroup(!canGoForward);\n                    if (GUI.Button(rect, \">\", EditorStyles.toolbarButton))\n                    {\n                        navigationHistory.GoForward();\n                        GUIUtility.ExitGUI(); // Prevent layout errors\n                    }\n                    EditorGUI.EndDisabledGroup();\n                    rect.x += IconW;\n                    \n                    // Lock/SmartLock button area - fixed width with text content\n                    rect.width = LockButtonW;\n                    \n                    {\n                        // Normal lock button with selection count\n                        UnityObject[] fr2CurrentSelection = GetFR2Selection();\n                        int selectionCount = fr2CurrentSelection?.Length ?? 0;\n                        \n                        // Split the button area - left side for selection info, right side for lock icon\n                        Rect selectionRect = rect;\n                        selectionRect.width = LockButtonW - 30f; // Leave space for lock icon\n                        \n                        Rect lockIconRect = rect;\n                        lockIconRect.x = selectionRect.xMax;\n                        lockIconRect.width = 30f;\n                        \n                        // Selection info button (clicking toggles selection visibility)\n                        string selectionText = selectionCount > 0 ? $\"Selection ({selectionCount})\" : \"Selection\";\n                        GUIContent selectionContent = new GUIContent(selectionText, \"Click to toggle selection panel\");\n                        \n                        // Highlight with subtle yellow if selection is out of sync\n                        Color originalBgColor = GUI.color;\n                        if (isSelectionOutOfSync)\n                        {\n                            GUI.color = new Color(1f, 1f, 0f, 1f); // Subtle yellow tint\n                        }\n                        \n                        if (GUI.Button(selectionRect, selectionContent, EditorStyles.toolbarButton))\n                        {\n                            settings.selection = !settings.selection;\n                            sp1.splits[0].visible = settings.selection;\n                            sp1.CalculateWeight();\n                            WillRepaint = true;\n                        }\n                        \n                        // Restore original background color\n                        GUI.color = originalBgColor;\n                        \n                        // Lock icon button (clicking locks/unlocks selection)\n                        GUIContent lockIconContent = new GUIContent(\n                            selection.isLock ? AssetFinderIcon.Lock.image : AssetFinderIcon.Unlock.image,\n                            selection.isLock ? \"Unlock Selection\" : \"Lock Selection\"\n                        );\n                        \n                        // Set green background when locked, similar to other toggle buttons\n                        Color originalBgColor2 = GUI.backgroundColor;\n                        if (selection.isLock)\n                        {\n                            GUI.backgroundColor = new Color(0.7f, 1f, 0.7f, 1f); // Same green as other toggle buttons\n                        }\n                        \n                        if (GUI.Button(lockIconRect, lockIconContent, EditorStyles.toolbarButton))\n                        {\n                            selection.isLock = !selection.isLock;\n                            WillRepaint = true;\n                        }\n                        \n                        // Restore original background color\n                        GUI.backgroundColor = originalBgColor2;\n                    }\n                },\n\n                AfterDraw = rect =>\n                {\n                    rect.xMin = rect.xMax - (IconW * 3 + BookmarkW);\n                    rect.width = IconW;\n\n                    // Scene toggle with content indication\n                    if (GUI2.ToolbarToggle(ref settings.scene, AssetFinderIcon.Scene.image, Vector2.zero, \"Show / Hide Scene References\", rect, ScenePanelHasContent()))\n                    {\n                        if ((settings.asset == false) && (settings.scene == false))\n                        {\n                            settings.asset = true;\n                            sp2.splits[1].visible = settings.asset;\n                        }\n\n                        RefreshPanelVisible();\n                        Repaint();\n                    }\n\n                    rect.x += IconW;\n                    if (GUI2.ToolbarToggle(ref settings.asset, AssetFinderIcon.Asset.image, Vector2.zero, \"Show / Hide Asset References\", rect, AssetPanelHasContent()))\n                    {\n                        if ((settings.asset == false) && (settings.scene == false))\n                        {\n                            settings.scene = true;\n                            sp2.splits[0].visible = settings.scene;\n                        }\n\n                        RefreshPanelVisible();\n                        Repaint();\n                    }\n\n                    rect.x += IconW;\n                    if (GUI2.ToolbarToggle(ref settings.details, AssetFinderIcon.Details.image, Vector2.zero, \"Show / Hide Details\", rect))\n                    {\n                        sp1.splits[2].visible = settings.details;\n                        sp1.CalculateWeight();\n                        Repaint();\n                    }\n\n                    rect.x += IconW;\n                    {\n                        rect.width = BookmarkW;\n                        int bookmarkCount = AssetFinderBookmark.Count;\n                        bool hasBookmarks = bookmarkCount > 0;\n\n                        Color originalBg = GUI.backgroundColor;\n                        if (hasBookmarks)\n                        {\n                            GUI.backgroundColor = new Color(0.7f, 1f, 0.7f, 1f);\n                        }\n\n                        var bookmarkTitle = AssetFinderGUIContent.FromTexture(AssetFinderIcon.Favorite.image, \"Show / Hide Bookmarks\");\n                        bookmarkTitle.text = hasBookmarks\n                            ? (bookmarkCount > 99 ? \"99+\" : $\"{bookmarkCount}\")\n                            : string.Empty;\n\n                        if (GUI2.ToolbarToggle(rect, ref settings.bookmark, bookmarkTitle))\n                        {\n                            sp1.splits[3].visible = settings.bookmark;\n                            sp1.CalculateWeight();\n                            Repaint();\n                        }\n                        \n                        GUI.backgroundColor = originalBg;\n                    }\n                }\n            };\n        }\n\n\n\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.Initialization.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9ab650bb105e74040b3f082e18327de6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.PanelSettings.cs",
    "content": "using System;\nusing System.Collections.Generic;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    partial class AssetFinderWindowAll\n    {\n        [Serializable] internal class PanelSettings\n        {\n            public bool selection;\n            public bool horzLayout;\n            public bool scene = true;\n            public bool asset = true;\n            public bool details;\n            public bool bookmark;\n            public bool toolMode;\n\n            public bool showFullPath = true;\n            public bool showFileSize;\n            public bool showFileExtension;\n            public bool showUsageType = true;\n            public bool writeImportLog;\n            public bool recursiveUnusedScan = true;\n\n            public AssetFinderRefDrawer.Mode toolGroupMode = AssetFinderRefDrawer.Mode.Type;\n            public AssetFinderRefDrawer.Mode groupMode = AssetFinderRefDrawer.Mode.Dependency;\n            public AssetFinderRefDrawer.Sort sortMode = AssetFinderRefDrawer.Sort.Path;\n\n            public int mainTabIndex = 1; // For main tabs (e.g. Uses/Used By/Addressables) - Default to \"Used By\"\n            public int toolTabIndex = 0; // For toolTabs (Duplicate/GUID/Unused/In Build/Others)\n            public int othersTabIndex = 0; // For vertical tab bar in 'Others' section\n\n            // Remember pixel sizes for fixed panels\n            public float selectionPanelPixel = 200f;\n            public float detailsPanelPixel = 150f;  \n            public float bookmarkPanelPixel = 150f;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.PanelSettings.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7756dd91425c7614ca453e83dbf68477\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SelectionManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        internal UnityObject[] _cachedSelection;\n        internal int _cachedSelectionFrame = -1;\n        private string[] ids;\n        \n        private void OnSelectionManagerChanged()\n        {\n            if (selection == null) return;\n            if (selection.isLock) return;\n            \n            // Check and consume ping lock state - if active, skip sync but hide warnings\n            bool hadPingLock = smartLock?.ConsumePingLockState() ?? false;\n            if (hadPingLock)\n            {\n                AssetFinderLOG.Log(\"Skipped refresh: Ping lock was active - keeping current FR2 selection!\");\n                \n                // Still need to check if selection is out of sync for UI highlighting\n                var unitySelection = AssetFinderSelectionManager.Instance.GetUnitySelection();\n                var fr2Selection = selection.GetUnityObjects();\n                isSelectionOutOfSync = !AreSelectionsEqual(unitySelection, fr2Selection);\n                \n                WillRepaint = true;\n                Repaint();\n                return;\n            }\n            \n            // IMPORTANT: Always update FR2 selection regardless of cache readiness\n            // Selection listening must work independently of cache status\n            \n            var shouldRefresh = smartLock.ShouldRefreshWithSmartLogic(this, selection.GetUnityObjects());\n            if (shouldRefresh)\n            {\n                selection.SyncFromGlobalSelection();\n                isSelectionOutOfSync = false; // Selection is now in sync\n                \n                // Only refresh FR2 view if cache is ready - this prevents errors but keeps selection updated\n                if (AssetFinderCache.isReady)\n                {\n                    RefreshFR2View();\n                }\n                else\n                {\n                    AssetFinderLOG.Log(\"Cache not ready - selection updated but view refresh skipped\");\n                }\n            }\n            else\n            {\n                isSelectionOutOfSync = true; // Selection is now out of sync\n            }\n            \n            WillRepaint = true;\n            Repaint();\n        }\n        \n        \n        private void OnDisableSelectionManager()\n        {\n            AssetFinderSelectionManager.SelectionChanged -= OnSelectionManagerChanged;\n        }\n        \n        public override void OnSelectionChange()\n        {\n            // DO NOTHING\n        }\n\n        void OnPanelSelectionChanged()\n        {\n            if (!AssetFinderCache.isReady) return;\n            if (SceneUsesDrawer == null) InitIfNeeded();\n            if (UsesDrawer == null) InitIfNeeded();\n            if (selection == null) return; // Additional safety check\n            \n            navigationHistory.SetWindow(this);\n\n            // Use unified selection manager (static access only)\n            UnityObject[] currentSelection = AssetFinderSelectionManager.Instance.GetUnitySelection();\n            \n            if (currentSelection.Length > 0)\n            {\n                navigationHistory.RecordSelection(currentSelection);\n            }\n            \n            if (isFocusingGUIDs)\n            {\n                if (guidObjs == null) guidObjs = new Dictionary<string, UnityObject>();\n                else guidObjs.Clear();\n                \n                for (var i = 0; i < currentSelection.Length; i++)\n                {\n                    UnityObject item = currentSelection[i];\n#if UNITY_2018_1_OR_NEWER\n                    {\n                        var guid = \"\";\n                        long fileid = -1;\n                        try\n                        {\n                            if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(item, out guid, out fileid))\n                            {\n                                guidObjs.Add(guid + \"/\" + fileid, currentSelection[i]);\n                            }\n                        }\n                        catch (Exception e)\n                        {\n                            AssetFinderLOG.LogWarning($\"TryGetGUIDAndLocalFileIdentifier {item}\\nException: {e}\");\n                        }\n                    }\n#else\n                    {\n                        var path = AssetDatabase.GetAssetPath(item);\n                        if (string.IsNullOrEmpty(path)) continue;\n                        var guid = AssetDatabase.AssetPathToGUID(path);\n                        System.Reflection.PropertyInfo inspectorModeInfo =\n                        typeof(SerializedObject).GetProperty(\"inspectorMode\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);\n\n                        SerializedObject serializedObject = new SerializedObject(item);\n                        inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null);\n\n                        SerializedProperty localIdProp =\n                            serializedObject.FindProperty(\"m_LocalIdentfierInFile\");\n\n                        var localId = localIdProp.longValue;\n                        if (localId <= 0)\n                        {\n                            localId = localIdProp.intValue;\n                        }\n                        if (localId <= 0)\n                        {\n                            continue;\n                        }\n                        if (!string.IsNullOrEmpty(guid)) guidObjs.Add(guid + \"/\" + localId, currentSelection[i]);\n                    }\n#endif\n                }\n            }\n\n            if (isFocusingUnused)\n            {\n                RefUnUse.ResetUnusedAsset(settings.recursiveUnusedScan);\n            }\n        }\n\n        internal void SetFR2Selection(UnityObject[] objects)\n        {\n            selection?.SetUnityObjects(objects);\n            \n            // Only refresh FR2 view if cache is ready - this prevents errors but keeps selection updated\n            if (AssetFinderCache.isReady)\n            {\n                RefreshFR2View();\n            }\n            else\n            {\n                AssetFinderLOG.Log(\"Cache not ready - selection updated but view refresh skipped in SetFR2Selection\");\n            }\n        }\n        \n        internal UnityObject[] GetFR2Selection()\n        {\n            return selection?.GetUnityObjects() ?? Array.Empty<UnityObject>();\n        }\n        \n        private void RefreshFR2View()\n        {\n            OnPanelSelectionChanged();\n            \n            // Only refresh selection view if we have a selection object\n            if (selection != null)\n            {\n                selection.RefreshView();\n            }\n            \n            // Refresh contextual messages based on current selection\n            if (this is AssetFinderWindowAll window)\n            {\n                window.RefreshContextualMessages();\n            }\n            \n            ids = Array.Empty<string>();\n            RefreshPanelVisible();\n\n            if (selection.isSelectingSceneObject)\n            {\n                // Get GameObjects from selection's instance IDs\n                var gameObjects = new List<UnityObject>();\n                foreach (string instIdStr in selection.instSet)\n                {\n                    if (int.TryParse(instIdStr, out int instId))\n                    {\n                        var obj = EditorUtility.InstanceIDToObject(instId);\n                        if (obj != null) gameObjects.Add(obj);\n                    }\n                }\n                \n                RefSceneInScene.ResetSceneInScene(gameObjects.OfType<GameObject>().ToArray());\n                SceneToAssetDrawer.Reset(gameObjects.OfType<GameObject>().ToArray(), true, true);\n                SceneUsesDrawer.ResetSceneUseSceneObjects(gameObjects.OfType<GameObject>().ToArray());\n            }\n            else if (selection.isSelectingAsset)\n            {\n                ids = selection.guidSet.ToArray();\n                \n                // These are the key calls that refresh the Uses/Used By tabs\n                UsesDrawer.Reset(ids, true);\n                UsedByDrawer.Reset(ids, false);\n                RefInScene.Reset(ids);\n                AddressableDrawer.RefreshView();\n            }\n        }\n\n#if UNITY_2018_OR_NEWER\n        private void OnSceneChanged(Scene arg0, Scene arg1)\n        {\n            if (IsFocusingFindInScene || IsFocusingSceneToAsset || IsFocusingSceneInScene)\n            {\n                OnSelectionChange();\n            }\n        }\n#endif\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SelectionManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d230407d4a38fca4aac642e7347be015\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SettingsPanel.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        private void DrawSettings()\n        {\n            if (bottomTabs == null || bottomTabs.current == -1) return;\n\n            GUILayout.BeginVertical(AssetFinderTheme.Current.SettingsPanelHeight);\n            {\n                GUILayout.Space(2f);\n                switch (bottomTabs.current)\n                {\n                case 0:\n                    {\n                        DrawMainSettings();\n                        break;\n                    }\n\n                case 1:\n                    {\n                        DrawIgnoreSettings();\n                        break;\n                    }\n\n                case 2:\n                    {\n                        DrawFilterSettings();\n                        break;\n                    }\n                }\n            }\n            GUILayout.EndVertical();\n\n            Rect rect = GUILayoutUtility.GetLastRect();\n            rect.height = 1f;\n            GUI2.Rect(rect, Color.black, 0.4f);\n        }\n\n        private void DrawMainSettings()\n        {\n            AssetFinderSetting.s.DrawSettings();\n\n            // Add the Write Import Log toggle in the settings\n            GUILayout.Space(5f);\n            EditorGUILayout.LabelField(\"Advanced Settings\", EditorStyles.boldLabel);\n\n            bool writeLog = settings.writeImportLog;\n            settings.writeImportLog = EditorGUILayout.Toggle(\"Write Import Log\", settings.writeImportLog);\n            if (writeLog != settings.writeImportLog)\n            {\n                EditorUtility.SetDirty(this);\n            }\n            \n            // Add Git settings if applicable\n            if (AssetFinderSettingExt.isGitProject)\n            {\n                DrawGitSettings();\n            }\n        }\n\n        private void DrawGitSettings()\n        {\n            GUILayout.Space(5f);\n            EditorGUILayout.LabelField(\"Git Settings\", EditorStyles.boldLabel);\n            \n            if (AssetFinderSettingExt.gitIgnoreAdded)\n            {\n                EditorGUILayout.HelpBox(\"AssetFinderCache.asset* is already in your .gitignore file.\", MessageType.Info);\n            }\n            else\n            {\n                EditorGUILayout.BeginHorizontal();\n                EditorGUILayout.LabelField(\"Add AssetFinderCache.asset* to .gitignore\");\n                if (GUILayout.Button(\"Apply\", AssetFinderTheme.Current.ApplyButtonWidth))\n                {\n                    AssetFinderGitUtil.AddFR2CacheToGitIgnore();\n                    AssetFinderSettingExt.gitIgnoreAdded = true;\n                    AssetFinderSettingExt.hideGitIgnoreWarning = true;\n                }\n                EditorGUILayout.EndHorizontal();\n            }\n        }\n\n        private void DrawIgnoreSettings()\n        {\n            if (AssetFinderAssetGroupDrawer.DrawIgnoreFolder()) \n            {\n                MarkDirty();\n            }\n        }\n\n        private void DrawFilterSettings()\n        {\n            if (AssetFinderAssetGroupDrawer.DrawSearchFilter()) \n            {\n                MarkDirty();\n            }\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.SettingsPanel.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3eceec0c15546f04e9d2c65d68a93449\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.ToolsPanel.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        private AssetFinderDeleteButton deleteUnused;\n\n        private void DrawTools()\n        {\n            if (isFocusingDuplicate)\n            {\n                Duplicated.DrawLayout();\n                GUILayout.FlexibleSpace();\n                return;\n            }\n\n            if (isFocusingUnused)\n            {\n                DrawUnusedAssetsPanel();\n                return;\n            }\n\n            if (isFocusingUsedInBuild)\n            {\n                UsedInBuild.DrawLayout();\n                return;\n            }\n\n            if (isFocusingOthers)\n            {\n                DrawOthersPanel();\n                return;\n            }\n\n            if (isFocusingGUIDs)\n            {\n                DrawGUIDs();\n            }\n        }\n\n        private void DrawUnusedAssetsPanel()\n        {\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.LabelField(\"Recursive Search\", AssetFinderTheme.Current.RecursiveSearchLabelWidth);\n            bool oldRecursive = settings.recursiveUnusedScan;\n            settings.recursiveUnusedScan = EditorGUILayout.Toggle(settings.recursiveUnusedScan, AssetFinderTheme.Current.ToggleWidth);\n            if (oldRecursive != settings.recursiveUnusedScan)\n            {\n                RefUnUse.ResetUnusedAsset(settings.recursiveUnusedScan);\n                EditorUtility.SetDirty(this);\n            }\n            EditorGUILayout.EndHorizontal();\n            \n            if ((RefUnUse.refs != null) && (RefUnUse.refs.Count == 0))\n            {\n                EditorGUILayout.HelpBox(\"Clean! Your project does not has have any unused assets!\", MessageType.Info);\n                GUILayout.FlexibleSpace();\n                EditorGUILayout.HelpBox(\"Your deleted assets was backup at Library/FR2/ just in case you want your assets back!\", MessageType.Info);\n            } \n            else\n            {\n                RefUnUse.DrawLayout();\n\n                if (deleteUnused == null)\n                {\n                    deleteUnused = new AssetFinderDeleteButton\n                    {\n                        warningMessage = \"A backup (.unitypackage) will be created so you can reimport the deleted assets later!\",\n                        deleteLabel = AssetFinderGUIContent.From(\"DELETE ASSETS\", AssetFinderIcon.Delete.image),\n                        confirmMessage = \"Create backup at Library/FR2/\"\n                    };\n                }\n\n                GUILayout.BeginHorizontal();\n                {\n                    deleteUnused.Draw(() => { AssetFinderUnity.BackupAndDeleteAssets(RefUnUse.source); });\n                }\n                GUILayout.EndHorizontal();\n            }\n        }\n\n        private void DrawOthersPanel()\n        {\n            GUILayout.Space(4f);\n            EditorGUILayout.BeginHorizontal();\n            \n            // Left: Vertical tab bar\n            EditorGUILayout.BeginVertical(AssetFinderTheme.Current.TabPanelWidth);\n            var tabStyle = new GUIStyle(EditorStyles.toolbarButton)\n            {\n                alignment = TextAnchor.MiddleLeft,\n                fixedHeight = 32f,\n                fontStyle = FontStyle.Normal\n            };\n            Color origColor = GUI.backgroundColor;\n            for (var i = 0; i < 3; i++)\n            {\n                string label = i == 0 ? \"Missing Scripts\" : i == 1 ? \"Organize Assets\" : \"Delete Empty Folders\";\n                GUI.backgroundColor = (settings.othersTabIndex == i) ? new Color(0.7f, 0.9f, 1f, 1f) : origColor;\n                if (GUILayout.Toggle(settings.othersTabIndex == i, label, tabStyle))\n                {\n                    if (settings.othersTabIndex != i) \n                    { \n                        settings.othersTabIndex = i; \n                        WillRepaint = true; \n                    }\n                }\n            }\n            GUILayout.FlexibleSpace();\n            GUI.backgroundColor = origColor;\n            EditorGUILayout.EndVertical();\n            \n            // Right: Tool content\n            EditorGUILayout.BeginVertical();\n            if (settings.othersTabIndex == 0) \n            { \n                MissingReference.DrawLayout(); \n            }\n            else if (settings.othersTabIndex == 1) \n            { \n                AssetOrganizer.DrawLayout(); \n            }\n            else \n            { \n                DeleteEmptyFolder.DrawLayout(); \n            }\n            EditorGUILayout.EndVertical();\n            EditorGUILayout.EndHorizontal();\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.ToolsPanel.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8a335a62fc282164b839db996dbc66c0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.UILayout.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll\n    {\n        internal AssetFinderRefDrawer[] _allDrawersCache;\n\n        private void OnCSVClickExtension()\n        {\n            AssetFinderRef[] csvSource = null;\n            AssetFinderRefDrawer drawer = GetAssetDrawer();\n\n            if (drawer != null) csvSource = drawer.source;\n\n            if (isFocusingUnused && (csvSource == null)) csvSource = RefUnUse.source;\n            if (isFocusingUsedInBuild && (csvSource == null)) csvSource = AssetFinderRef.FromDict(UsedInBuild.refs);\n            if (isFocusingDuplicate && (csvSource == null)) csvSource = AssetFinderRef.FromList(Duplicated.list);\n\n            AssetFinderExport.ExportCSV(csvSource);\n        }\n\n        private void RefreshPanelVisible()\n        {\n            if (sp2 == null) InitIfNeeded();\n            if (sp2 == null) return;\n\n            sp2.splits[0].visible = isScenePanelVisible;\n            sp2.splits[1].visible = isAssetPanelVisible;\n            sp2.splits[2].visible = isFocusingAddressable;\n            sp2.CalculateWeight();\n        }\n\n        private void RefreshShowFullPath()\n        {\n            if (_allDrawersCache != null)\n            {\n                foreach (var drawer in _allDrawersCache)\n                {\n                    if (drawer != null && drawer.Config != null) drawer.Config.showFullPath = settings.showFullPath;\n                }\n            }\n        }\n\n        private void RefreshShowFileSize()\n        {\n            if (_allDrawersCache != null)\n            {\n                foreach (var drawer in _allDrawersCache)\n                {\n                    if (drawer != null && drawer.AssetConfig != null) drawer.AssetConfig.showFileSize = settings.showFileSize;\n                }\n            }\n        }\n\n        private void RefreshShowFileExtension()\n        {\n            if (_allDrawersCache == null) return;\n            foreach (var drawer in _allDrawersCache)\n            {\n                if (drawer != null && drawer.AssetConfig != null) drawer.AssetConfig.showExtension = settings.showFileExtension;\n            }\n        }\n\n        private void MarkDirty()\n        {\n            if (_allDrawersCache != null)\n            {\n                foreach (var drawer in _allDrawersCache)\n                {\n                    drawer?.SetDirty();\n                }\n            }\n            Duplicated.SetDirty();\n            UsedInBuild.SetDirty();\n            AddressableDrawer.RefreshSort();\n            WillRepaint = true;\n        }\n\n        private void RefreshSort()\n        {\n            if (_allDrawersCache != null)\n            {\n                foreach (var drawer in _allDrawersCache)\n                {\n                    drawer?.RefreshSort();\n                }\n            }\n            AddressableDrawer.RefreshSort();\n            Duplicated.RefreshSort();\n            UsedInBuild.RefreshSort();\n            \n            // Ensure tool-specific drawers are also refreshed\n            if (settings.toolMode)\n            {\n                RefUnUse?.RefreshSort();\n            }\n        }\n\n        private AssetFinderRefDrawer GetAssetDrawer()\n        {\n            if (isFocusingUses) return IsSelectingAssets ? UsesDrawer : SceneToAssetDrawer;\n            if (isFocusingUsedBy) return IsSelectingAssets ? UsedByDrawer : null;\n            if (isFocusingAddressable) return AddressableDrawer.drawer;\n            return null;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.UILayout.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1201bb63b0c94244a85cfeb56f797f20\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal partial class AssetFinderWindowAll : AssetFinderWindowBase, IHasCustomMenu\n    {\n        [SerializeField] internal PanelSettings settings = new PanelSettings();\n\n        [MenuItem(\"Sunflower/Asset Finder/Show Window %#K\")]\n        internal static void ShowWindow()\n        {\n            var _window = CreateInstance<AssetFinderWindowAll>();\n            _window.InitIfNeeded();\n            AssetFinderUnity.SetWindowTitle(_window, \"Asset Finder\");\n            _window.Show();\n        }\n\n        [NonSerialized] internal AssetFinderBookmark bookmark;\n        [NonSerialized] internal AssetFinderSelection selection;\n        [NonSerialized] internal AssetFinderUsedInBuild UsedInBuild;\n        [NonSerialized] internal AssetFinderDuplicateTree2 Duplicated;\n        [NonSerialized] internal AssetFinderRefDrawer RefUnUse;\n        [NonSerialized] internal AssetFinderMissingReference MissingReference;\n        [NonSerialized] internal AssetFinderAssetOrganizer AssetOrganizer;\n        [NonSerialized] internal AssetFinderDeleteEmptyFolder DeleteEmptyFolder;\n\n        [NonSerialized] internal AssetFinderRefDrawer UsesDrawer; // [Selected Assets] are [USING] (depends on / contains reference to) ---> those assets\n        [NonSerialized] internal AssetFinderRefDrawer UsedByDrawer; // [Selected Assets] are [USED BY] <---- those assets \n        [NonSerialized] internal AssetFinderRefDrawer SceneToAssetDrawer; // [Selected GameObjects in current Scene] are [USING] ---> those assets\n        [NonSerialized] internal AssetFinderAddressableDrawer AddressableDrawer;\n\n\n        [NonSerialized] internal AssetFinderRefDrawer RefInScene; // [Selected Assets] are [USED BY] <---- those components in current Scene \n        [NonSerialized] internal AssetFinderRefDrawer SceneUsesDrawer; // [Selected GameObjects] are [USING] ---> those components / GameObjects in current scene\n        [NonSerialized] internal AssetFinderRefDrawer RefSceneInScene; // [Selected GameObjects] are [USED BY] <---- those components / GameObjects in current scene\n        \n        [NonSerialized] internal AssetFinderSmartLock smartLock = new AssetFinderSmartLock();\n        [NonSerialized] private AssetFinderNavigationHistory navigationHistory = new AssetFinderNavigationHistory();\n\n        // AssetFinderTheme singleton provides centralized UI constants\n        [NonSerialized] internal AssetFinderTheme theme;\n\n        // Simple flag to track selection sync status for UI highlighting\n        [NonSerialized] internal bool isSelectionOutOfSync;\n        \n        // Cached contextual messages for drawers\n        [NonSerialized] private string cachedUsesMessage;\n        [NonSerialized] private string cachedUsedByMessage;\n        [NonSerialized] private string cachedRefInSceneMessage;\n        [NonSerialized] private string cachedSceneUsesMessage;\n        [NonSerialized] private string cachedSceneToAssetMessage;\n        [NonSerialized] private string cachedSceneInSceneMessage;\n        [NonSerialized] private UnityObject[] lastCachedSelection;\n\n        private string GetSceneContextInfo()\n        {\n#if UNITY_2021_2_OR_NEWER\n            // Unity 2021.2+ moved PrefabStageUtility to UnityEditor.SceneManagement\n            var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();\n            if (prefabStage != null)\n            {\n                string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabStage.assetPath);\n                return $\"current Prefab ({prefabName})\";\n            }\n#elif UNITY_2018_3_OR_NEWER\n            // Unity 2018.3 - 2021.1 had PrefabStageUtility in UnityEditor.Experimental.SceneManagement\n            var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage();\n            if (prefabStage != null)\n            {\n#if UNITY_2020_1_OR_NEWER\n                string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabStage.assetPath);\n#else\n                string prefabName = System.IO.Path.GetFileNameWithoutExtension(prefabStage.prefabAssetPath);\n#endif\n                return $\"current Prefab ({prefabName})\";\n            }\n#endif\n            \n            // Check scene count\n            int sceneCount = UnityEngine.SceneManagement.SceneManager.sceneCount;\n            if (sceneCount == 0)\n            {\n                return \"current scene\";\n            }\n            else if (sceneCount == 1)\n            {\n                var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();\n                if (scene.IsValid() && !string.IsNullOrEmpty(scene.name))\n                {\n                    return $\"current scene ({scene.name})\";\n                }\n                return \"current scene\";\n            }\n            else\n            {\n                return \"current scenes\"; // Multiple scenes\n            }\n        }\n\n        public void Reload()\n        {\n            InitializeComponents();\n        }\n\n        private GUIContent GetScenePanelTitle()\n        {\n            string titleText = \"Scene\";\n            string tooltip = \"Scene references\";\n\n            // Check scene status for title text modifications\n            if (AssetFinderSceneCache.Api != null)\n            {\n                switch (AssetFinderSceneCache.Api.Status)\n                {\n                    case SceneCacheStatus.Scanning:\n                        int cur = AssetFinderSceneCache.Api.current;\n                        int total = AssetFinderSceneCache.Api.total;\n                        if (total > 0)\n                        {\n                            titleText += $\" (scanning {cur}/{total})\";\n                            tooltip = $\"Currently scanning scene objects: {cur} of {total}\";\n                        }\n                        else\n                        {\n                            titleText += \" (scanning...)\";\n                            tooltip = \"Currently scanning scene objects\";\n                        }\n                        break;\n                    case SceneCacheStatus.None:\n                        titleText += \" (not ready)\";\n                        tooltip = \"Scene cache is not initialized\";\n                        break;\n                    case SceneCacheStatus.Changed:\n                        tooltip = \"Scene changed - results might be incomplete\";\n                        break;\n                    case SceneCacheStatus.Ready:\n                        tooltip = \"Scene cache ready\";\n                        break;\n                }\n            }\n\n            return new GUIContent(titleText, AssetFinderIcon.Scene.image, tooltip);\n        }\n\n        private GUIContent GetAssetPanelTitle()\n        {\n            string titleText = \"Assets\";\n            string tooltip = \"Asset references\";\n\n            // Check asset status for title text modifications\n            if (AssetFinderCache.Api == null) return new GUIContent(titleText, AssetFinderIcon.Asset.image, tooltip);\n            \n            if (!AssetFinderCache.isReady)\n            {\n                titleText += \" (processing...)\";\n                tooltip = $\"Processing assets: {(AssetFinderCache.Api.progress * 100):F0}%\";\n            }\n            else if (AssetFinderCache.Api.HasChanged)\n            {\n                tooltip = \"Assets changed - cache needs refresh\";\n            }\n            else if (AssetFinderCache.Api.workCount > 0)\n            {\n                tooltip = \"Processing assets in background\";\n            }\n            else if (HasUnscannedAssets())\n            {\n                tooltip = \"Some assets not scanned yet - refresh cache to scan\";\n            }\n            else\n            {\n                tooltip = \"Asset cache ready\";\n            }\n            \n            return new GUIContent(titleText, AssetFinderIcon.Asset.image, tooltip);\n        }\n\n        \n        private bool ScenePanelHasContent()\n        {\n            if (!AssetFinderSceneCache.hasCache) return false;\n            \n            // Check if scene panel would have content based on current selection\n            AssetFinderRefDrawer drawer = isFocusingUses\n                ? IsSelectingAssets ? null : SceneUsesDrawer\n                : IsSelectingAssets ? RefInScene : RefSceneInScene;\n                \n            return drawer != null && drawer.source != null && drawer.source.Length > 0;\n        }\n        \n        private bool AssetPanelHasContent()\n        {\n            if (!AssetFinderCache.isReady) return false;\n            \n            // Check if asset panel would have content based on current selection\n            AssetFinderRefDrawer drawer = GetAssetDrawer();\n            return drawer != null && drawer.source != null && drawer.source.Length > 0;\n        }\n        \n        private bool BookmarkPanelHasContent()\n        {\n            return bookmark != null && AssetFinderBookmark.Count > 0;\n        }\n\n        private bool IsScenePanelDirty()\n        {\n            if (AssetFinderSceneCache.Api == null) return false;\n            \n            // Show yellow title for various scene issues\n            return AssetFinderSceneCache.Api.Status == SceneCacheStatus.Changed ||\n                   AssetFinderSceneCache.Api.Status == SceneCacheStatus.None ||\n                   AssetFinderSceneCache.Api.Status == SceneCacheStatus.Scanning;\n        }\n\n        private bool IsAssetPanelDirty()\n        {\n            if (AssetFinderCache.Api == null) return false;\n            \n            // Show yellow title when:\n            // 1. Cache is not ready (still processing)\n            // 2. Has pending changes that need refresh\n            // 3. Has work in progress\n            // 4. Has unscanned assets (never been processed)\n            return !AssetFinderCache.isReady || \n                   AssetFinderCache.Api.HasChanged || \n                   AssetFinderCache.Api.workCount > 0 ||\n                   HasUnscannedAssets();\n        }\n\n        private bool HasUnscannedAssets()\n        {\n            if (AssetFinderCache.Api?.AssetList == null) return false;\n            \n            // Check if there are any critical assets that have never been scanned\n            // Since folders are no longer in AssetList, we only check scannable assets\n            foreach (var asset in AssetFinderCache.Api.AssetList)\n            {\n                if (asset.IsCriticalAsset() && !asset.hasBeenScanned)\n                {\n                    return true;\n                }\n            }\n            \n            return false;\n        }\n\n        private string GetSceneStatusMessage()\n        {\n            if (AssetFinderSceneCache.Api == null) return null;\n\n            switch (AssetFinderSceneCache.Api.Status)\n            {\n                case SceneCacheStatus.Changed:\n                    return \"Scene changed - results might be incomplete\";\n                case SceneCacheStatus.Scanning:\n                    return \"Scanning scene objects...\";\n                case SceneCacheStatus.None:\n                    return \"Scene cache not ready\";\n                default:\n                    return null;\n            }\n        }\n\n        private string GetAssetStatusMessage()\n        {\n            if (AssetFinderCache.Api == null) return null;\n\n            if (AssetFinderCache.Api.HasChanged)\n            {\n                return \"Assets changed - cache needs refresh\";\n            }\n            else if (AssetFinderCache.Api.workCount > 0)\n            {\n                return $\"Processing {AssetFinderCache.Api.workCount} assets...\";\n            }\n            else if (!AssetFinderCache.isReady)\n            {\n                return \"Asset cache not ready\";\n            }\n\n            return null;\n        }\n        protected bool lockSelection => (selection != null) && selection.isLock;\n\n        // Helper properties to access unified selection manager\n        private bool IsSelectingAssets => selection?.isSelectingAsset ?? false;\n        private bool IsSelectingSceneObjects => selection?.isSelectingSceneObject ?? false;\n\n        private bool IsSelectionOutOfSync\n        {\n            get\n            {\n                if (selection == null) return false;\n                \n                var unitySelection = AssetFinderSelectionManager.Instance.GetUnitySelection();\n                var fr2Selection = selection.GetUnityObjects();\n                \n                // Check count difference\n                if (unitySelection.Length != fr2Selection.Length) return true;\n                \n                // Check content difference (order doesn't matter for warning)\n                var unitySet = new HashSet<UnityObject>(unitySelection);\n                var fr2Set = new HashSet<UnityObject>(fr2Selection);\n                \n                return !unitySet.SetEquals(fr2Set);\n            }\n        }\n        \n        private void RefreshContextualMessages()\n        {\n            var currentSelection = GetFR2Selection();\n            \n            // Only regenerate if selection actually changed\n            if (AreSelectionsEqual(lastCachedSelection, currentSelection)) return;\n            \n            lastCachedSelection = currentSelection;\n            \n            cachedUsesMessage = GenerateContextualMessage(currentSelection, \"USING\");\n            cachedUsedByMessage = GenerateContextualMessage(currentSelection, \"USED BY\");\n            cachedRefInSceneMessage = GenerateContextualMessage(currentSelection, \"USED BY\", \" any GameObjects in current scene\");\n            cachedSceneUsesMessage = GenerateContextualMessage(currentSelection, \"USING\", \" any other objects\");\n            cachedSceneToAssetMessage = GenerateContextualMessage(currentSelection, \"USING\", \" any assets\");\n            cachedSceneInSceneMessage = GenerateContextualMessage(currentSelection, \"USED BY\", \" any other GameObjects\");\n        }\n\n        private void ClearAllCachedUIElements()\n        {\n            // Clear cached contextual messages\n            cachedUsesMessage = null;\n            cachedUsedByMessage = null;\n            cachedRefInSceneMessage = null;\n            cachedSceneUsesMessage = null;\n            cachedSceneToAssetMessage = null;\n            cachedSceneInSceneMessage = null;\n            lastCachedSelection = null;\n        }\n        \n        private string GenerateContextualMessage(UnityObject[] objects, string action, string suffix = \" any other assets\")\n        {\n            if (objects == null || objects.Length == 0)\n                return $\"Nothing selected is {action}{suffix}!\";\n            \n            // Replace \"current scene\" with contextual info for scene-related messages\n            if (suffix.Contains(\"current scene\"))\n            {\n                suffix = suffix.Replace(\"current scene\", GetSceneContextInfo());\n            }\n            \n            // Check if any selected assets are ignored\n            var ignoredAssets = new List<string>();\n            var nonIgnoredAssets = new List<UnityObject>();\n            \n            foreach (var obj in objects)\n            {\n                if (AssetDatabase.Contains(obj))\n                {\n                    string assetPath = AssetDatabase.GetAssetPath(obj);\n                    bool isIgnored = AssetFinderSetting.IgnoreAsset.Any(ignore =>\n                        assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) ||\n                        assetPath.StartsWith(ignore + \"/\", StringComparison.OrdinalIgnoreCase));\n                    \n                    if (isIgnored)\n                        ignoredAssets.Add(obj.name);\n                    else\n                        nonIgnoredAssets.Add(obj);\n                }\n                else\n                {\n                    nonIgnoredAssets.Add(obj);\n                }\n            }\n            \n            // If all selected assets are ignored, show special message\n            if (ignoredAssets.Count > 0 && nonIgnoredAssets.Count == 0)\n            {\n                if (objects.Length == 1)\n                {\n                    return $\"{objects[0].name} is in the ignore list and won't show references!\";\n                }\n                else\n                {\n                    return $\"All {objects.Length} selected assets are in the ignore list and won't show references!\";\n                }\n            }\n            \n            // If some are ignored, show mixed message\n            if (ignoredAssets.Count > 0)\n            {\n                string baseMessage = GenerateBasicMessage(nonIgnoredAssets.ToArray(), action, suffix);\n                return $\"{baseMessage} ({ignoredAssets.Count} ignored asset{(ignoredAssets.Count > 1 ? \"s\" : \"\")} not shown)\";\n            }\n            \n            // Normal case - no ignored assets\n            return GenerateBasicMessage(objects, action, suffix);\n        }\n        \n        private string GenerateBasicMessage(UnityObject[] objects, string action, string suffix)\n        {\n            if (objects == null || objects.Length == 0)\n                return $\"Nothing selected is {action}{suffix}!\";\n            \n            // Check if this is a scene-related message - skip asset scan status for scene references\n            bool isSceneRelated = suffix.Contains(\"GameObjects\") || suffix.Contains(\"other objects\");\n            \n            if (objects.Length == 1)\n            {\n                var obj = objects[0];\n                string name = obj.name;\n                string typeName = GetFriendlyTypeName(obj);\n                \n                bool isAsset = AssetDatabase.Contains(obj);\n                if (isAsset)\n                {\n                    string assetPath = AssetDatabase.GetAssetPath(obj);\n                    if (Directory.Exists(assetPath))\n                    {\n                        return $\"{name} does not use any other assets!\";\n                    }\n                    \n                    // Check if this asset is non-critical (ignored, packages, built-in)\n                    string guid = AssetDatabase.AssetPathToGUID(assetPath);\n                    var asset = AssetFinderCache.Api?.Get(guid);\n                    \n                    // bool isPackageAsset = assetPath.StartsWith(\"Packages/\");\n                    bool isIgnoredAsset = AssetFinderSetting.IgnoreAsset.Any(ignore =>\n                        assetPath.Equals(ignore, StringComparison.OrdinalIgnoreCase) ||\n                        assetPath.StartsWith(ignore + \"/\", StringComparison.OrdinalIgnoreCase));\n                    bool isBuiltInAsset = asset != null && AssetFinderAsset.BUILT_IN_ASSETS.Contains(asset.guid);\n                    bool isNonCritical = asset != null && !asset.IsCriticalAsset();\n                    \n                    // For \"USING\" tab - show special message for non-critical assets\n                    if (action == \"USING\" && (isIgnoredAsset || isBuiltInAsset || isNonCritical))\n                    {\n                        // if (isPackageAsset)\n                        //     return $\"{name} usage is skipped (Package asset)\";\n                        if (isIgnoredAsset)\n                            return $\"{name} usage is skipped (Ignored asset)\";\n                        if (isBuiltInAsset)\n                            return $\"{name} usage is skipped (Built-in asset)\";\n                        return $\"{name} usage is skipped (Non-critical asset)\";\n                    }\n                    \n                    // For \"USED BY\" tab - never show content scan messages, only show if truly no references\n                    if (action == \"USED BY\")\n                    {\n                        return $\"{name} is not {action}{suffix}!\";\n                    }\n                    \n                    // Skip asset scan status checks for scene-related messages\n                    if (!isSceneRelated)\n                    {\n                        var assetStatus = GetAssetScanStatus(assetPath);\n                        if (assetStatus.isNonScannable)\n                        {\n                            return $\"{name} does not use any other assets!\";\n                        }\n                        if (assetStatus.needsScanning)\n                        {\n                            return $\"{name} not scanned yet - hit Refresh for complete results!\";\n                        }\n                        if (assetStatus.isDirty)\n                        {\n                            return $\"{name} content changed - hit Refresh for complete results!\";\n                        }\n                    }\n                    \n                    return $\"{name} is not {action}{suffix}!\";\n                }\n                else\n                {\n                    return $\"{typeName} '{name}' is not {action}{suffix}!\";\n                }\n            }\n            else\n            {\n                string selectionSummary = GenerateSelectionSummary(objects);\n                \n                // For \"USED BY\" tab with multiple assets - never show content scan messages\n                if (action == \"USED BY\")\n                {\n                    return $\"{selectionSummary} are not {action}{suffix}!\";\n                }\n                \n                // Skip asset scan status checks for scene-related messages\n                if (!isSceneRelated)\n                {\n                    var scanStatus = GetMultipleAssetsScanStatus(objects);\n                    \n                    if (scanStatus.allUnscanned)\n                    {\n                        return $\"{selectionSummary} not scanned yet - hit Refresh for complete results!\";\n                    }\n                    else if (scanStatus.allDirty)\n                    {\n                        return $\"{selectionSummary} content changed - hit Refresh for complete results!\";\n                    }\n                    else if (scanStatus.hasMixed)\n                    {\n                        return $\"{selectionSummary} need scanning - hit Refresh for complete results!\";\n                    }\n                }\n                \n                return $\"{selectionSummary} are not {action}{suffix}!\";\n            }\n        }\n        \n        private string GenerateSelectionSummary(UnityObject[] objects)\n        {\n            var typeCounts = new Dictionary<string, int>();\n            \n            foreach (var obj in objects)\n            {\n                string typeName = GetFriendlyTypeName(obj);\n                if (typeCounts.ContainsKey(typeName))\n                    typeCounts[typeName]++;\n                else\n                    typeCounts[typeName] = 1;\n            }\n            \n            // Sort by count (descending) then by name for consistent ordering\n            var sortedTypes = typeCounts.OrderByDescending(kvp => kvp.Value)\n                                       .ThenBy(kvp => kvp.Key)\n                                       .ToList();\n            \n            if (sortedTypes.Count == 1)\n            {\n                var kvp = sortedTypes[0];\n                return $\"{kvp.Value} selected {GetPluralTypeName(kvp.Key, kvp.Value)}\";\n            }\n            else if (sortedTypes.Count <= 3)\n            {\n                // Show up to 3 types: \"2 Materials, 1 Texture2D, 3 GameObjects\"\n                var parts = sortedTypes.Select(kvp => $\"{kvp.Value} {GetPluralTypeName(kvp.Key, kvp.Value)}\");\n                return string.Join(\", \", parts);\n            }\n            else\n            {\n                // Too many types, show total count: \"15 selected objects\"\n                return $\"{objects.Length} selected objects\";\n            }\n        }\n        \n        private string GetFriendlyTypeName(UnityObject obj)\n        {\n            if (obj == null) return \"Unknown\";\n            \n            // Special cases for better names\n            var type = obj.GetType();\n            string typeName = type.Name;\n            \n            // Handle common Unity types with better names\n            switch (typeName)\n            {\n                case \"Texture2D\": return \"Texture2D\";\n                case \"Material\": return \"Material\";\n                case \"AudioClip\": return \"Audio Clip\";\n                case \"GameObject\": return \"GameObject\";\n                case \"MonoScript\": return \"Script\";\n                case \"DefaultAsset\":\n                    // For folders and other default assets\n                    if (AssetDatabase.IsValidFolder(AssetDatabase.GetAssetPath(obj)))\n                        return \"Folder\";\n                    return \"Asset\";\n                case \"Sprite\": return \"Sprite\";\n                case \"Mesh\": return \"Mesh\";\n                case \"Shader\": return \"Shader\";\n                case \"AnimationClip\": return \"Animation\";\n                case \"Cubemap\": return \"Cubemap\";\n                case \"Font\": return \"Font\";\n                case \"TextAsset\": return \"Text Asset\";\n                case \"ScriptableObject\": return \"Scriptable Object\";\n                case \"Prefab\": return \"Prefab\";\n                default:\n                    // Clean up namespace if present\n                    if (typeName.Contains('.'))\n                        typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);\n                    return typeName;\n            }\n        }\n        \n        private string GetPluralTypeName(string typeName, int count)\n        {\n            if (count <= 1) return typeName;\n            \n            // Handle specific pluralization rules\n            switch (typeName.ToLower())\n            {\n                case \"gameobject\": return \"GameObjects\";\n                case \"material\": return \"Materials\";\n                case \"texture2d\": return \"Texture2Ds\";\n                case \"audio clip\": return \"Audio Clips\";\n                case \"script\": return \"Scripts\";\n                case \"folder\": return \"Folders\";\n                case \"sprite\": return \"Sprites\";\n                case \"mesh\": return \"Meshes\";\n                case \"shader\": return \"Shaders\";\n                case \"animation\": return \"Animations\";\n                case \"cubemap\": return \"Cubemaps\";\n                case \"font\": return \"Fonts\";\n                case \"text asset\": return \"Text Assets\";\n                case \"scriptable object\": return \"Scriptable Objects\";\n                case \"prefab\": return \"Prefabs\";\n                default:\n                    // Generic pluralization - just add 's'\n                    return typeName + \"s\";\n            }\n        }\n\n        private (bool isNonScannable, bool needsScanning, bool isDirty) GetAssetScanStatus(string assetPath)\n        {\n            string guid = AssetDatabase.AssetPathToGUID(assetPath);\n            \n            if (!AssetFinderCache.isReady || AssetFinderCache.Api == null)\n                return (false, false, false);\n                \n            var asset = AssetFinderCache.Api.Get(guid, true);\n            if (asset == null)\n                return (false, false, false);\n            \n            \n            \n            bool isNonScannable = asset.type == AssetFinderAsset.AssetType.DLL ||\n                                 asset.type == AssetFinderAsset.AssetType.SCRIPT ||\n                                 asset.type == AssetFinderAsset.AssetType.NON_READABLE ||\n                                 !asset.IsCriticalAsset();\n            \n            \n            \n            bool needsScanning = !asset.hasBeenScanned;\n            bool isDirty = asset.isDirty;\n            \n//            Debug.Log($\"GetAssetScanStatus: {assetPath} -->\\n isNonScannable: {isNonScannable} | needScanning: {needsScanning} | isDirty = {asset.isDirty}\");\n            return (isNonScannable, needsScanning && !isNonScannable, isDirty && !isNonScannable);\n        }\n        \n        private (bool allUnscanned, bool allDirty, bool hasMixed) GetMultipleAssetsScanStatus(UnityObject[] objects)\n        {\n            if (!AssetFinderCache.isReady || AssetFinderCache.Api == null)\n                return (false, false, false);\n            \n\t\t\tbool hasUnscannedAssets = false;\n\t\t\tbool hasDirtyAssets = false;\n\t\t\tbool hasRegularAssets = false;\n            \n            foreach (var obj in objects)\n            {\n                if (!AssetDatabase.Contains(obj)) continue;\n                \n                string assetPath = AssetDatabase.GetAssetPath(obj);\n                string guid = AssetDatabase.AssetPathToGUID(assetPath);\n                var asset = AssetFinderCache.Api.Get(guid, true);\n                if (asset == null) continue;\n\t\t\t\t\n\t\t\t\tbool isNonScannable = asset.type == AssetFinderAsset.AssetType.DLL ||\n\t\t\t\t\t\t\t\t  asset.type == AssetFinderAsset.AssetType.SCRIPT ||\n\t\t\t\t\t\t\t\t  asset.type == AssetFinderAsset.AssetType.NON_READABLE ||\n\t\t\t\t\t\t\t\t  !asset.IsCriticalAsset();\n\t\t\t\t\n\t\t\t\tif (isNonScannable)\n\t\t\t\t{\n\t\t\t\t\thasRegularAssets = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbool neverScanned = !asset.hasBeenScanned;\n\t\t\t\tbool isDirty = asset.isDirty;\n\t\t\t\t\n\t\t\t\tif (neverScanned)\n\t\t\t\t\thasUnscannedAssets = true;\n\t\t\t\telse if (isDirty)\n\t\t\t\t\thasDirtyAssets = true;\n\t\t\t\telse\n\t\t\t\t\thasRegularAssets = true;\n            }\n            \n            bool allUnscanned = hasUnscannedAssets && !hasDirtyAssets && !hasRegularAssets;\n            bool allDirty = hasDirtyAssets && !hasUnscannedAssets && !hasRegularAssets;\n            bool hasMixed = (hasUnscannedAssets || hasDirtyAssets) && hasRegularAssets;\n            \n            return (allUnscanned, allDirty, hasMixed);\n        }\n        \n        private static bool AreSelectionsEqual(UnityObject[] selection1, UnityObject[] selection2)\n        {\n            if (selection1 == null && selection2 == null) return true;\n            if (selection1 == null || selection2 == null) return false;\n            if (selection1.Length != selection2.Length) return false;\n            \n            var set1 = new HashSet<UnityObject>(selection1);\n            var set2 = new HashSet<UnityObject>(selection2);\n            return set1.SetEquals(set2);\n        }\n\n        private void OnEnable()\n        {\n            AssetFinderUnity.RefreshEditorStatus();\n            wantsMouseMove = true;\n\n            // Initialize theme based on current Unity skin (needed because it's NonSerialized)\n            theme = EditorGUIUtility.isProSkin ? AssetFinderTheme.Dark : AssetFinderTheme.Light;\n\n            // Initialize selection manager early\n            InitializeSelectionManager();\n\n            RegisterSceneCacheCallbacks();\n            AssetFinderCache.onReady -= OnAssetCacheReady;\n            AssetFinderCache.onReady += OnAssetCacheReady;\n            UpdateSceneCacheAutoRefresh();\n            Repaint();\n        }\n\n        private void OnDisable()\n        {\n            UnregisterSceneCacheCallbacks();\n            OnDisableSelectionManager();\n            \n            // Cleanup selection event subscription\n            if (selection != null)\n            {\n                selection.OnSelectionChanged -= OnLocalSelectionChanged;\n            }\n\n            AssetFinderCache.onReady -= OnAssetCacheReady;\n        }\n\n        private void OnFocus()\n        {\n            AssetFinderUnity.RefreshEditorStatus();\n        }\n\n        private void RegisterSceneCacheCallbacks()\n        {\n            AssetFinderSceneCache.onReady -= OnSceneCacheReady;\n            AssetFinderSceneCache.onReady += OnSceneCacheReady;\n        }\n\n        private void UnregisterSceneCacheCallbacks()\n        {\n            AssetFinderSceneCache.onReady -= OnSceneCacheReady;\n        }\n\n        private void OnSceneCacheReady()\n        {\n            WillRepaint = true;\n\n            // Clear cached UI elements when scene cache is refreshed\n            ClearAllCachedUIElements();\n\n            // Always refresh FR2 panels when scene cache finishes scanning\n            // This ensures Uses/UsedBy panels show updated results for current selection\n            RefreshFR2View();\n            \n            // If selection was out of sync due to cache not being ready, sync now\n            if (isSelectionOutOfSync && selection != null && !selection.isLock)\n            {\n                selection.SyncFromGlobalSelection();\n                RefreshFR2View();\n                isSelectionOutOfSync = false;\n            }\n        }\n\n        private void OnAssetCacheReady()\n        {\n            WillRepaint = true;\n            ClearAllCachedUIElements();\n            RefreshFR2View();\n        }\n\n\n        private void UpdateSceneCacheAutoRefresh()\n        {\n            if (AssetFinderSceneCache.Api != null) AssetFinderSceneCache.Api.AutoRefresh = AssetFinderSettingExt.isAutoRefreshEnabled;\n        }\n\n        protected void InitIfNeeded()\n        {\n            if (UsesDrawer != null) return;\n            InitializeComponents();\n        }\n\n        private bool ValidateLockedSelection()\n        {\n            if (!lockSelection) return true;\n            \n            var currentFR2Selection = GetFR2Selection();\n            if (currentFR2Selection == null || currentFR2Selection.Length == 0)\n            {\n                UnlockAndSyncSelection();\n                return false;\n            }\n\n            var validObjects = currentFR2Selection.Where(obj => obj != null).ToArray();\n\n            if (validObjects.Length == 0)\n            {\n                UnlockAndSyncSelection();\n                RefreshFR2View();\n                return false;\n            }\n\n            if (validObjects.Length != currentFR2Selection.Length)\n            {\n                SetFR2Selection(validObjects);\n                return true;\n            }\n            \n            return true;\n        }\n\n        private void UnlockAndSyncSelection()\n        {\n            selection.isLock = false;\n            selection.SyncFromGlobalSelection();\n            isSelectionOutOfSync = false;\n        }\n        \n        private bool isScenePanelVisible\n        {\n            get\n            {\n                if (isFocusingAddressable) return false;\n\n                if (IsSelectingAssets && isFocusingUses) return false;\n                if (!IsSelectingAssets && isFocusingUsedBy) return true;\n\n                return settings.scene;\n            }\n        }\n        \n        private bool isAssetPanelVisible\n        {\n            get\n            {\n                if (isFocusingAddressable) return false;\n\n                if (IsSelectingAssets && isFocusingUses) return true;\n                if (!IsSelectingAssets && isFocusingUsedBy) return false;\n\n                return settings.asset;\n            }\n        }\n\n\n        [NonSerialized] public AssetFinderSplitView sp1; // container : Selection / sp2 / Bookmark \n        [NonSerialized] public AssetFinderSplitView sp2; // Scene / Assets\n        \n        [NonSerialized] private AssetFinderTabView tabs;\n        [NonSerialized] private AssetFinderTabView toolTabs;\n        [NonSerialized] private AssetFinderTabView bottomTabs;\n        [NonSerialized] private AssetFinderSearchView search;\n\n        private void DrawScene(Rect rect)\n        {\n            DrawScenePanel(rect);\n        }\n    \n        private void DrawAsset(Rect rect)\n        {\n            DrawAssetPanel(rect);\n        }\n\n        private void DrawSearch()\n        {\n            if (search == null) search = new AssetFinderSearchView();\n            search.DrawLayout();\n        }\n\n        private void DrawSelectionPanel(Rect rect)\n        {\n            if (selection == null) return;\n            selection.Draw(rect);\n        }\n\n        private void DrawDetailsPanel(Rect rect)\n        {\n            var drawer = GetActiveDrawer();\n            if (drawer != null)\n            {\n                drawer.DrawDetails(rect);\n            }\n            else\n            {\n                EditorGUI.HelpBox(rect, \"No details available - select an item in the main panel to see details\", MessageType.Info);\n            }\n        }\n\n        private AssetFinderRefDrawer GetActiveDrawer()\n        {\n            if (isFocusingUses)\n            {\n                return IsSelectingAssets ? UsesDrawer : SceneUsesDrawer;\n            }\n            else if (isFocusingUsedBy)\n            {\n                return IsSelectingAssets ? UsedByDrawer : RefSceneInScene;\n            }\n            return null;\n        }\n\n        protected override void OnGUI()\n        {\n            OnGUI2();\n        }\n\n\n        internal void ToggleDetailsPanel()\n        {\n            settings.details = !settings.details;\n            if (sp1 != null && sp1.splits != null && sp1.splits.Count > 2)\n            {\n                sp1.splits[2].visible = settings.details;\n                sp1.CalculateWeight();\n            }\n            Repaint();\n        }\n\n\n\n        public bool isFocusingUses => tabs?.IsFocusing(0) ?? false;\n        public bool isFocusingUsedBy => tabs?.IsFocusing(1) ?? false;\n        public bool isFocusingAddressable => tabs?.IsFocusing(2) ?? false;\n\n        // \n        public bool isFocusingDuplicate => toolTabs?.IsFocusing(0) ?? false;\n        public bool isFocusingGUIDs => toolTabs?.IsFocusing(1) ?? false;\n        public bool isFocusingUnused => toolTabs?.IsFocusing(2) ?? false;\n        public bool isFocusingUsedInBuild => toolTabs?.IsFocusing(3) ?? false;\n        public bool isFocusingOthers => toolTabs?.IsFocusing(4) ?? false;\n\n        private static readonly HashSet<AssetFinderRefDrawer.Mode> allowedModes = new HashSet<AssetFinderRefDrawer.Mode>\n        {\n            AssetFinderRefDrawer.Mode.Type,\n            AssetFinderRefDrawer.Mode.Extension,\n            AssetFinderRefDrawer.Mode.Folder\n        };\n\n        private void OnTabChange()\n        {\n            if (deleteUnused != null) deleteUnused.hasConfirm = false;\n            if (UsedInBuild != null) UsedInBuild.SetDirty();\n\n            // Fix: Refresh panel visibility when switching between Uses/Used By tabs\n            RefreshPanelVisible();\n            \n            // Force refresh drawers when tab changes to ensure content is displayed\n            // Only skip if cache not ready or selection is null\n            if (AssetFinderCache.isReady && selection != null)\n            {\n                RefreshFR2View();\n            }\n        }\n\n\n        protected bool DrawFooter()\n        {\n            bottomTabs.DrawLayout();\n            var bottomBar = GUILayoutUtility.GetLastRect();\n            bottomBar = bottomBar.LPad(theme.FooterButtonsOffset); // offset for left buttons\n\n            var (fullPathRect, flex1) = bottomBar.ExtractLeft(theme.IconButtonSize);\n            var (fileSizeRect, flex2) = flex1.ExtractLeft(theme.IconButtonSize);\n            var (extensionRect, flex3) = flex2.ExtractLeft(theme.IconButtonSize);\n            var (buttonRect, flex4) = flex3.ExtractRight(theme.IconButtonSize);\n\n            var viewModeRect = flex4.RPad(theme.IconButtonSize).SetWidth(theme.ViewModeSelectorWidthValue);\n            viewModeRect.x = flex4.xMax - 224f;\n\n            DrawViewModes(viewModeRect);\n            DrawButton(buttonRect, ref settings.toolMode, AssetFinderIcon.CustomTool);\n            if (DrawButton(fullPathRect, ref settings.showFullPath, AssetFinderIcon.FullPath)) RefreshShowFullPath();\n\n            if (DrawButton(fileSizeRect, ref settings.showFileSize, AssetFinderIcon.Filesize)) RefreshShowFileSize();\n\n            if (DrawButton(extensionRect, ref settings.showFileExtension, AssetFinderIcon.FileExtension))\n                RefreshShowFileExtension();\n\n            return false;\n        }\n\n\n\n\n        // Save status to temp variable so the result will be consistent between Layout & Repaint\n        internal static int delayRepaint;\n        internal static bool checkDrawImportResult;\n\n\n        protected void OnGUI2()\n        {\n            if (Event.current.type == EventType.Layout)\n            {\n                AssetFinderUnity.RefreshEditorStatus();\n                ValidateLockedSelection();\n            }\n\n            if (Event.current.type == EventType.MouseMove || Event.current.type == EventType.ScrollWheel || Event.current.type == EventType.MouseLeaveWindow || Event.current.type == EventType.MouseEnterWindow)\n            {\n                WillRepaint = true;\n            }\n\n            if (AssetFinderSettingExt.disable)\n            {\n                DrawEnable();\n                return;\n            }\n\n            if (AssetFinderSettingExt.isAutoRefreshEnabled && !AssetFinderSceneCache.hasInit) AssetFinderSceneCache.Api.RefreshCache(true);\n\n            UpdateSceneCacheAutoRefresh();\n\n            if (!AssetFinderCacheHelper.inited) AssetFinderCacheHelper.InitHelper();\n            \n            var result = CheckDrawImport();\n            if (Event.current.type == EventType.Layout) checkDrawImportResult = result;\n\n            if (!checkDrawImportResult) return;\n\n            if (settings.toolMode)\n            {\n                if (!AssetFinderSettingExt.hideToolsWarning)\n                {\n                    EditorGUILayout.BeginHorizontal();\n                    EditorGUILayout.HelpBox(AssetFinderGUIContent.From(\n                        \"Tools are POWERFUL & DANGEROUS! Only use if you know what you are doing!!!\",\n                        AssetFinderIcon.Warning.image));\n                    if (GUILayout.Button(\"  x\", EditorStyles.label, theme.CloseButtonWidth, theme.WarningCloseButtonHeight))\n                        AssetFinderSettingExt.hideToolsWarning = true;\n\n                    EditorGUILayout.EndHorizontal();\n                }\n\n                DrawGitWarningPanel();\n\n                toolTabs.DrawLayout();\n                DrawTools();\n            }\n            else\n            {\n                DrawGitWarningPanel();\n\n                tabs.DrawLayout();\n                sp1.DrawLayout();\n                StorePanelPixels();\n            }\n\n            DrawSettings();\n            DrawFooter();\n            \n            if (sp1.hasResize && Event.current.type == EventType.Repaint)\n            {\n                var selectionInfo = sp1.splits[0];\n                var detailsInfo = sp1.splits[2];\n                var bookmarkInfo = sp1.splits[3];\n                if (selectionInfo.visible) settings.selectionPanelPixel = Mathf.Max(selectionInfo.minPixel, selectionInfo.preferredPixel);\n                if (detailsInfo.visible) settings.detailsPanelPixel = Mathf.Max(detailsInfo.minPixel, detailsInfo.preferredPixel);\n                if (bookmarkInfo.visible) settings.bookmarkPanelPixel = Mathf.Max(bookmarkInfo.minPixel, bookmarkInfo.preferredPixel);\n                EditorUtility.SetDirty(this);\n            }\n\n            if (!WillRepaint) return;\n            WillRepaint = false;\n            Repaint();\n        }\n\n        private void StorePanelPixels()\n        {\n            if (sp1 == null || sp1.splits == null || sp1.splits.Count == 0) return;\n            var selectionInfo = sp1.splits[0];\n            if (selectionInfo.visible)\n            {\n                settings.selectionPanelPixel = Mathf.Max(selectionInfo.minPixel, selectionInfo.rect.width);\n            }\n            if (sp1.splits.Count > 2)\n            {\n                var detailsInfo = sp1.splits[2];\n                if (detailsInfo.visible)\n                {\n                    settings.detailsPanelPixel = Mathf.Max(detailsInfo.minPixel, detailsInfo.rect.width);\n                }\n            }\n            if (sp1.splits.Count > 3)\n            {\n                var bookmarkInfo = sp1.splits[3];\n                if (bookmarkInfo.visible)\n                {\n                    settings.bookmarkPanelPixel = Mathf.Max(bookmarkInfo.minPixel, bookmarkInfo.rect.width);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowAll.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 57d9cbcdaeab0d745953a66ddc225bd9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowBase.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n    public abstract class AssetFinderWindowBase : EditorWindow, IWindow\n    {\n        public bool WillRepaint { get; set; }\n        protected bool showFilter, showIgnore;\n\n        //[NonSerialized] protected bool lockSelection;\n        //[NonSerialized] internal List<AssetFinderAsset> Selected;\n\n        public void AddItemsToMenu(GenericMenu menu)\n        {\n            var api = AssetFinderCache.Api;\n            if (api == null) return;\n\n            menu.AddDisabledItem(AssetFinderGUIContent.FromString(\"AssetFinder - ref2.6.4\"));\n            menu.AddSeparator(string.Empty);\n\n            menu.AddItem(AssetFinderGUIContent.FromString(\"Enable\"), !AssetFinderSettingExt.disable, () => { AssetFinderSettingExt.disable = !AssetFinderSettingExt.disable; });\n            menu.AddItem(AssetFinderGUIContent.FromString($\"Auto Refresh: {AssetFinderSettingExt.autoRefreshMode}\"), AssetFinderSettingExt.isAutoRefreshEnabled, () =>\n            {\n                AssetFinderSettingExt.autoRefreshMode = AssetFinderSettingExt.isAutoRefreshEnabled ? AssetFinderAutoRefreshMode.Off : AssetFinderAutoRefreshMode.On;\n                if (AssetFinderSettingExt.autoRefreshMode == AssetFinderAutoRefreshMode.On)\n                {\n                    AssetFinderCache.Api.IncrementalRefresh();\n                }\n            });\n            \n            menu.AddItem(AssetFinderGUIContent.FromString($\"Refresh\"), false, () =>\n            {\n                AssetFinderCache.Api.ClearCacheCompletely();\n                AssetFinderCache.Api.Check4Changes(true);\n            });\n\n            menu.AddSeparator(string.Empty);\n            \n            // Developer mode toggle\n            bool isDebugMode = AssetFinderDefine.IsDebugModeEnabled();\n            menu.AddItem(AssetFinderGUIContent.FromString($\"Developer Mode\"), isDebugMode, () =>\n            {\n                AssetFinderDefine.ToggleDebugMode(!isDebugMode);\n            });\n\n            AddToCustomMenu(menu);\n        }\n        \n        public abstract void AddToCustomMenu(GenericMenu menu);\n\n        public abstract void OnSelectionChange();\n        protected abstract void OnGUI();\n\n#if UNITY_2018_OR_NEWER\n        protected void OnSceneChanged(Scene arg0, Scene arg1)\n        {\n            if (IsFocusingFindInScene || IsFocusingSceneToAsset || IsFocusingSceneInScene)\n            {\n                OnSelectionChange();\n            }\n        }\n#endif\n\n        protected bool DrawEnable()\n        {\n            AssetFinderCache api = AssetFinderCache.Api;\n            if (api == null) return false;\n            if (!AssetFinderSettingExt.disable) return true;\n\n            bool isPlayMode = EditorApplication.isPlayingOrWillChangePlaymode;\n            string message = isPlayMode\n                ? \"Find References 2 is disabled in play mode!\"\n                : \"Find References 2 is disabled!\";\n\n            EditorGUILayout.HelpBox(AssetFinderGUIContent.From(message, AssetFinderIcon.Warning.image));\n            if (GUILayout.Button(AssetFinderGUIContent.FromString(\"Enable\")))\n            {\n                AssetFinderSettingExt.disable = !AssetFinderSettingExt.disable;\n                if (!AssetFinderSettingExt.disable && AssetFinderCache.Api != null)\n                {\n                    AssetFinderCache.Api.IncrementalRefresh();\n                }\n                Repaint();\n            }\n\n            return false;\n        }\n\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/AssetFinderWindowBase.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b0f5dd186be864a489cf1712d6297c5d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/IRefDraw.cs",
    "content": "using UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal interface IRefDraw\n    {\n        IWindow window { get; }\n        int ElementCount();\n        bool DrawLayout();\n        bool Draw(Rect rect);\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/IRefDraw.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8eabb463923a4f67b4e3e1ef63ec2bc4\ntimeCreated: 1746370625"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/IWindow.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    public interface IWindow\n    {\n        bool WillRepaint { get; set; }\n        void Repaint();\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window/IWindow.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 005f5270e708458d8f5e137822248058\ntimeCreated: 1746370637"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script/Window.meta",
    "content": "fileFormatVersion: 2\nguid: 283461c5abe8449f98f9b196b50d0e4b\ntimeCreated: 1746366625"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Script.meta",
    "content": "fileFormatVersion: 2\nguid: 9124b66e19b3c44bf999ad7566fa6450\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Virtuesky.Sunflower.AssetFinder.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.AssetFinder.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"Unity.Addressables\",\n        \"Virtuesky.Sunflower.DataStorage.Editor\",\n        \"VirtueSky.Sunflower.Inspector\",\n        \"Unity.Addressables.Editor\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [\n        {\n            \"name\": \"com.unity.addressables\",\n            \"expression\": \"0.0.0\",\n            \"define\": \"AssetFinderADDRESSABLE\"\n        },\n        {\n            \"name\": \"com.unity.visualeffectgraph\",\n            \"expression\": \"0.0.0\",\n            \"define\": \"ASSET_USAGE_VFX_GRAPH\"\n        }\n    ],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/Virtuesky.Sunflower.AssetFinder.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 8579ab42c9ab63d4bac5fb07bd390b46\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/AssetFinder.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetFileInfo\n    {\n        public readonly string assetPath;\n\n        public bool exists;\n        public string fileExt;\n        public string fileName;\n        public long fileSize;\n        public string folder;\n        \n        public AssetFileInfo(string guid)\n        {\n            assetPath = AssetDatabase.GUIDToAssetPath(guid) + \"/\";\n            fileName = Path.GetFileNameWithoutExtension(assetPath);\n            fileExt = \".\" + Path.GetExtension(assetPath);\n            if (string.IsNullOrWhiteSpace(assetPath))\n            {\n                exists = false;\n                return;\n            }\n\n            exists = File.Exists(assetPath);\n            if (!exists) return;\n\n            fileSize = new FileInfo(assetPath).Length;\n            folder = Path.GetDirectoryName(assetPath);\n        }\n    }\n\n    internal class AssetFolder\n    {\n        private static readonly Dictionary<string, AssetFolder> map = new Dictionary<string, AssetFolder>();\n\n        public string guid;\n        public string path;\n        public static AssetFolder Get(string guid)\n        {\n            return map.GetValueOrDefault(guid);\n        }\n        public static AssetFolder Create(string guid)\n        {\n            string path = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(path)) return null;\n\n            var folder = new AssetFolder { guid = guid, path = path };\n            map[guid] = folder;\n            return folder;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/AssetFinder.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f77ff3449563f4fccb4f9f89b2516c9a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetDB.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [Serializable] internal class AssetFinderAssetDB\n    {\n        [SerializeField] internal List<AssetFinderAssetFile> files = new List<AssetFinderAssetFile>();\n        [SerializeField] internal List<AssetFinderIDRef> refs = new List<AssetFinderIDRef>();\n        \n        [NonSerialized] internal readonly Dictionary<string, AssetFinderAssetFile> guidMap = new Dictionary<string, AssetFinderAssetFile>();\n        [NonSerialized] internal bool isReady;\n        [NonSerialized] internal AssetFinderTimeSlice readContentTS;\n\n        internal AssetFinderAssetFile GetAssetByGUID(string guid)\n        {\n            return guidMap.GetValueOrDefault(guid);\n        }\n        private AssetFinderAssetFile AddAsset(string guid)\n        {\n            string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(assetPath)) return null;\n            var assetFile = new AssetFinderAssetFile(guid, files.Count);\n            guidMap.Add(guid, assetFile);\n            files.Add(assetFile);\n            return assetFile;\n        }\n\n        internal AssetFinderAssetFile GetAsset(AssetFinderID id)\n        {\n            return files[id.AssetIndex];\n        }\n        \n        internal AssetFinderAssetDB Clear()\n        {\n            files.Clear();\n            refs.Clear();\n            guidMap.Clear();\n            return this;\n        }\n\n        internal void Scan(bool force = false)\n        {\n            if (force) Clear();\n            string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();\n            foreach (string path in allAssetPaths)\n            {\n                if (path.Contains(\"FindReference2\") || path.Contains(\"AssetFinderCache\")) continue;\n                \n                string guid = AssetDatabase.AssetPathToGUID(path);\n                // if (path.StartsWith(\"Packages/\", StringComparison.InvariantCulture))\n                // {\n                //     AssetFinderLOG.Log($\"Skip assets in Packages: {guid} --> {path}\");\n                //     continue;\n                // }\n                \n                if (AssetDatabase.IsValidFolder(path))\n                {\n                    AssetFinderLOG.Log($\"Skip Folder: {guid} --> {path}\");\n                    continue;\n                }\n                if (AssetFinderParser.IsReadable(path)) AddAsset(guid);\n            }\n            \n            ReadContent();\n        }\n        \n        internal void ReadContent()\n        {\n            int count = files.Count;\n            if (readContentTS == null) readContentTS = new AssetFinderTimeSlice(() => count, TS_ReadFileContent, FinishReadContent);\n            readContentTS.Start();\n        }\n\n        void FinishReadContent()\n        {\n            // Save refs\n            refs.Clear();\n            guidMap.Clear();\n            \n            for (var i =0;i < files.Count; i++)\n            {\n                AssetFinderAssetFile assetFile = files[i];\n                guidMap.Add(assetFile.guid, assetFile);\n                refs.AddRange(assetFile.usage);\n            }\n            isReady = true;\n        }\n\n        internal void BuildCache()\n        {\n            guidMap.Clear();\n            for (var i = 0; i < files.Count; i++)\n            {\n                AssetFinderAssetFile assetFile = files[i];\n                if (assetFile == null) continue;\n                \n                assetFile.fileIdMap.Clear();\n                foreach (long fileId in assetFile.fileIds.Distinct())\n                {\n                    assetFile.fileIdMap.Add(fileId, assetFile.fileIds.IndexOf(fileId));\n                }\n                \n                guidMap.Add(assetFile.guid, assetFile);\n                assetFile.usage.Clear();\n                assetFile.usedBy.Clear();\n            }\n\n            for (var i = 0; i < refs.Count; i++)\n            {\n                AssetFinderIDRef r = refs[i];\n                AssetFinderAssetFile from = GetAsset(r.fromId.WithoutSubAssetIndex());\n                AssetFinderAssetFile to = GetAsset(r.toId.WithoutSubAssetIndex());\n                \n                if (from == null || to == null)\n                {\n                    Debug.LogWarning($\"Invalid reference (asset not found???): {r.fromId} --> {r.toId}\");\n                    continue;\n                }\n                \n                from.usage.Add(r);\n                to.usedBy.Add(r);\n            }\n            \n            isReady = true;\n        }\n        \n        internal void TS_ReadFileContent(int index)\n        {\n            AssetFinderAssetFile sourceFile = files[index];\n            string assetPath = AssetDatabase.GUIDToAssetPath(sourceFile.guid);\n            if (string.IsNullOrEmpty(assetPath)) return;\n\n            var usage = new HashSet<AssetFinderID>();\n            AssetFinderParser.ReadContent(assetPath, (guid, fileId) =>\n            {\n                if (guid == sourceFile.guid) return; // Skip self reference\n                AssetFinderAssetFile destFile = GetAssetByGUID(guid) ?? AddAsset(guid);\n                if (destFile == null) return; // Invalid or missing GUID???\n\n                int subAssetIndex = destFile.Get(fileId);\n                if (subAssetIndex == -1) subAssetIndex = destFile.Add(fileId);\n                \n                AssetFinderID toFR2Id = destFile.fr2Id.WithSubAssetIndex(subAssetIndex);\n                if (!usage.Add(toFR2Id)) return; // Already added\n\n                var r = new AssetFinderIDRef() { fromId = sourceFile.fr2Id, toId = toFR2Id };\n                sourceFile.usage.Add(r);\n                destFile.usedBy.Add(r);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetDB.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 21cc30678bacede4d9a6013ff74557b3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetFile.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [Serializable] internal class AssetFinderAssetFile\n    {\n        [SerializeField] internal AssetFinderID fr2Id;\n        [SerializeField] internal string guid;\n        [SerializeField] internal List<long> fileIds = new List<long> { 0 };\n\n        // Some assets has detail, some does not\n        [SerializeField] internal List<SubAssetDetail> subDetails = new List<SubAssetDetail>();\n\n        // Cache\n        [NonSerialized] internal readonly Dictionary<long, int> fileIdMap = new Dictionary<long, int>(); // map fileId => index\n        [NonSerialized] internal readonly List<AssetFinderIDRef> usage = new List<AssetFinderIDRef>();\n        [NonSerialized] internal readonly List<AssetFinderIDRef> usedBy = new List<AssetFinderIDRef>();\n        \n        public AssetFinderAssetFile()\n        { }\n        public AssetFinderAssetFile(string guid, int assetIndex)\n        {\n            this.guid = guid;\n            fr2Id = new AssetFinderID(assetIndex, 0, false);\n        }\n        \n        internal int Get(long fileId)\n        {\n            return fileIdMap.GetValueOrDefault(fileId, -1);\n        }\n        internal int Add(long fileId)\n        {\n            int idx = fileIds.Count;\n            fileIdMap.Add(fileId, idx);\n            fileIds.Add(fileId);\n            return idx;\n        }\n\n        internal SubAssetDetail GetSubDetail(long fileId)\n        {\n            return subDetails.Find(item=>item.fileId == fileId);\n        }\n\n        public void LoadAllSubAssetsIfNeeded()\n        {\n            if (subDetails != null && subDetails.Count > 0) return;\n            if (fileIds.Count <= 1) return;\n            LoadAllSubAssets();\n        }\n        \n        private void LoadAllSubAssets()\n        {\n            subDetails.Clear();\n            if (string.IsNullOrEmpty(guid))\n            {\n                AssetFinderLOG.LogWarning(\"Invalid asset GUID.\");\n                return;\n            }\n\n            // Convert GUID to Asset Path\n            string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(assetPath))\n            {\n                AssetFinderLOG.LogWarning($\"No sub asset found for GUID: {guid}\");\n                return;\n            }\n            \n            UnityObject[] subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(assetPath);\n            foreach (UnityObject subAsset in subAssets)\n            {\n                if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(subAsset, out _, out long localFileID))\n                {\n                    subDetails.Add(new SubAssetDetail(localFileID, subAsset));\n                }\n            }\n            \n            AssetFinderCacheAsset.MarkAsDirty();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderAssetFile.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1ad1ec70aa912124da3b61e7ef7fb0d9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderCacheAsset.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Serialization;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [CreateAssetMenu]\n    internal class AssetFinderCacheAsset : ScriptableObject\n    {\n        // static APIs\n        private static AssetFinderCacheAsset _api;\n        public static bool isReady => _api != null && _api.db.isReady;\n\n        internal static void MarkAsDirty()\n        {\n            if (_api == null) return;\n            EditorUtility.SetDirty(_api);\n        }\n        \n        public static AssetFinderAssetFile GetFile(string guid) => _api.db.GetAssetByGUID(guid);\n        \n        public static List<AssetFinderIDRef> CollectUsage(string guid, List<AssetFinderIDRef> result = null)\n        {\n            if (result == null) result = new List<AssetFinderIDRef>();\n            if (!isReady)\n            {\n                AssetFinderLOG.Log($\"CacheAsset is not ready!\");\n                return result;\n            }\n\n            AssetFinderAssetFile assetFile = GetFile(guid);\n            if (assetFile == null)\n            {\n                Debug.Log($\"Asset not found in cache: {guid} : {AssetDatabase.GUIDToAssetPath(guid)}\");\n                return result;\n            }\n            \n            result.AddRange(assetFile.usage);\n            return result;\n        }\n        public static List<AssetFinderIDRef> CollectUsedBy(string guid, long fileId = -1, List<AssetFinderIDRef> result = null) // -1 = all\n        {\n            if (result == null) result = new List<AssetFinderIDRef>();\n            if (!isReady)\n            {\n                AssetFinderLOG.Log($\"CacheAsset is not ready!\");\n                return result;\n            }\n            \n            AssetFinderAssetFile assetFile = _api.db.GetAssetByGUID(guid);\n            if (assetFile == null)\n            {\n                Debug.Log($\"Asset not found in cache: {guid} : {AssetDatabase.GUIDToAssetPath(guid)}\");\n                return result;\n            }\n            \n            int subAssetIndex = fileId < 0 ? -1 : assetFile.Get(fileId);\n            // Debug.Log($\"CollectUsedBy: {guid}:{fileId} ({subAssetIndex} --> {AssetDatabase.GUIDToAssetPath(guid)} | Count = {assetFile.usedBy.Count}\");\n            if (fileId <= 0 || subAssetIndex <= 0)\n            {\n                result.AddRange(assetFile.usedBy);\n            } else\n            {\n                result.AddRange(assetFile.usedBy.Where(a=> a.toId.SubAssetIndex == subAssetIndex));\n            }\n            \n            return result;\n        }\n        \n        public static (string guid, long fileId) GetGuidAndFileId(AssetFinderID fr2ID)\n        {\n            if (!isReady) return (null, -1);\n            \n            AssetFinderAssetFile assetFile = _api.db.GetAsset(fr2ID);\n            if (assetFile == null)\n            {\n                AssetFinderLOG.Log($\"Asset not found in cache: {fr2ID}\");\n                return (null, -1);\n            }\n\n            return (assetFile.guid, assetFile.fileIds[fr2ID.SubAssetIndex]);\n        }\n        \n        \n        \n        \n        // Serializable\n        [FormerlySerializedAs(\"sampleAsset\")] [SerializeField] private AssetFinderIDRef sampleID = new AssetFinderIDRef();\n        [SerializeField] internal AssetFinderAssetDB db = new AssetFinderAssetDB();\n        [SerializeField] internal List<string> dirtyAssets = new List<string>();\n        \n        internal static void Init(AssetFinderCacheAsset cache)\n        {\n            _api = cache;\n            _api.db.isReady = false;\n\n            if (_api.dirtyAssets.Count > 0)\n            {\n                // Do check for changes\n            }\n            \n            _api.db.BuildCache();\n        }\n        \n        // Scan\n        [ContextMenu(\"Scan\")]\n        internal void Scan()\n        {\n            db.isReady = false;\n            db.Scan(true);\n            EditorUtility.SetDirty(this);\n        }\n        \n        [ContextMenu(\"BuildCache\")]\n        internal void BuildCache()\n        {\n            db.isReady = false;\n            db.BuildCache();\n            EditorUtility.SetDirty(this);\n        }\n\n        [ContextMenu(\"Start Debug\")]\n        internal void StartDebug()\n        {\n            AssetFinderUSelection.StartDebugReference();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderCacheAsset.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 73b9f1e1c240309488b132c85916b957\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderID.cs",
    "content": "using System;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n   [StructLayout(LayoutKind.Sequential)]\n   [Serializable] \n   public struct AssetFinderID: IEquatable<AssetFinderID>\n   {\n       private const int SCENE_FLAG_BIT = 31;\n       private const int SUB_INDEX_SHIFT = 21;\n       private const uint SUB_INDEX_MASK = 0x3FFu << SUB_INDEX_SHIFT;\n       private const uint MAIN_INDEX_MASK = 0x1FFFFFu;\n       \n       [SerializeField] private int value;\n        \n       private uint uValue\n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => unchecked((uint)value);\n           \n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           set => this.value = unchecked((int)value);\n       }\n       \n       private AssetFinderID(int pValue)\n       {\n           value = pValue;\n       }\n       \n       public AssetFinderID(int mainIndex, int subIndex, bool isSceneObject)\n       {\n           if (mainIndex < 0 || mainIndex >= (1 << 21))\n           {\n               throw new ArgumentOutOfRangeException(nameof(mainIndex));\n           }\n           if (subIndex < 0 || subIndex >= (1 << 10))\n           {\n               throw new ArgumentOutOfRangeException(nameof(subIndex));\n           }\n\n           uint u = ( (uint)(isSceneObject ? 1 : 0) << SCENE_FLAG_BIT)\n               | ((uint)subIndex << SUB_INDEX_SHIFT)\n               | ((uint)mainIndex & MAIN_INDEX_MASK);\n           value = unchecked((int)u);\n       }\n\n       [MethodImpl(MethodImplOptions.AggressiveInlining)]\n       public AssetFinderID WithoutSubAssetIndex() => WithSubAssetIndex(0);\n       \n       [MethodImpl(MethodImplOptions.AggressiveInlining)]\n       public AssetFinderID WithSubAssetIndex(int subIndex)\n       {   \n           return new AssetFinderID(MainIndex, subIndex, IsSceneObject);\n       }\n       \n       public bool IsSceneObject\n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => (uValue & (1u << SCENE_FLAG_BIT)) != 0;\n       } \n       private int MainIndex \n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => (int)(uValue & MAIN_INDEX_MASK);\n       }\n       \n       private int SubIndex \n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => (int)((uValue & SUB_INDEX_MASK) >> SUB_INDEX_SHIFT);\n       } \n       \n       public int AssetIndex\n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get  => MainIndex;\n       } \n       \n       public int SubAssetIndex\n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => SubIndex;\n       } \n       public int GameObjectIndex\n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => MainIndex; \n       } \n       public int ComponentIndex\n       {\n           [MethodImpl(MethodImplOptions.AggressiveInlining)]\n           get => SubIndex;\n       } \n\n       public static implicit operator int(AssetFinderID id) => id.value;\n       public static implicit operator AssetFinderID(int value) => new AssetFinderID(value);\n\n       public override int GetHashCode() => value;\n       public bool Equals(AssetFinderID other) => value == other.value;\n       public override bool Equals(object obj) => obj is AssetFinderID other && Equals(other);\n       \n       public override string ToString() => IsSceneObject\n           ? $\"SceneObject - GameObjectIndex: {GameObjectIndex}, ComponentIndex: {ComponentIndex}\"\n           : $\"Asset - AssetIndex: {AssetIndex}, SubAssetIndex: {SubAssetIndex}\";\n           \n       // private sealed class Comparer : IEqualityComparer<AssetFinderID>\n       // {\n       //     public static readonly Comparer Instance = new Comparer();\n       //     public bool Equals(AssetFinderID x, AssetFinderID y) => x.serializedValue == y.serializedValue;\n       //     public int GetHashCode(AssetFinderID obj) => obj.serializedValue;\n       // }\n   }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderID.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2ae340b075e4caf4f8acd2068ca8f27f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderIDRef.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [Serializable] internal class AssetFinderIDRef\n    {\n        [SerializeField] internal AssetFinderID fromId;\n        [SerializeField] internal AssetFinderID toId;\n        \n        // public string type; // The class that reference this asset\n        // public string path; // The property path that the class used to reference to asset\n        // public bool isWeak; // Weak: Addressable / Atlas\n\n        public override string ToString()\n        {\n            return $\"{fromId.ToString()} -> {toId.ToString()}\";\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderIDRef.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9729cd2c8a35f2647927a913eba11dc6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderSceneObject.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    public class AssetFinderSceneObject\n    {\n        \n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/AssetFinderSceneObject.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 445ef92693ec9b144956feabd217ac09\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/SubAssetDetail.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Audio;\nusing UnityEngine.Video;\nusing Object = UnityEngine.Object;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal enum SubAssetType\n    {\n        Unknown,\n        Sprite, // Part of a multi-sprite texture or sprite atlas\n        Mesh, // Extracted from FBX, OBJ, or Blender files\n        GameObject, // Child of prefab\n        Material, // Can be embedded inside FBX models\n        ScriptableObject, // Nested ScriptableObjects\n        \n        AnimationClip, // From FBX models or Animation files\n        Avatar, // Humanoid Avatar inside an FBX model\n        AudioMixerSnapshot, // Part of an Audio Mixer\n        LightingDataAsset, // Generated lighting data\n        BlendShape, // Internal morph target data from FBX\n        PhysicsMaterial2D, // Sometimes stored inside assets\n        ShaderVariantCollection, // Shader variant sub-assets\n        TerrainLayer, // Used in Terrain systems\n        Texture2DArray, // Array of textures stored inside a single asset\n        Texture3D, // 3D texture data (e.g., volumetric effects)\n        Cubemap, // Used in reflection probes\n        VideoClip, // If part of a larger asset\n        SpineAnimation, // Sub-asset in Spine skeleton data\n        SpineSkeletonData, // Spine skeleton metadata\n    }\n    \n    [Serializable] internal class SubAssetDetail\n    {\n        public long fileId;\n        public string name;\n        public SubAssetType type;\n\n        public SubAssetDetail(long fileId, Object subAsset)\n        {\n            this.fileId = fileId;\n            name = subAsset.name;\n            type = GetSubAssetType(subAsset);\n        }\n        \n        // Direct Type Mapping (UnityEngine types)\n        private static readonly Dictionary<Type, SubAssetType> TypeToSubAssetType = new Dictionary<Type, SubAssetType>\n        {\n            { typeof(Sprite), SubAssetType.Sprite },\n            { typeof(Mesh), SubAssetType.Mesh },\n            { typeof(GameObject), SubAssetType.GameObject },\n            { typeof(AnimationClip), SubAssetType.AnimationClip },\n            { typeof(Avatar), SubAssetType.Avatar },\n            { typeof(Material), SubAssetType.Material },\n            { typeof(AudioMixerSnapshot), SubAssetType.AudioMixerSnapshot },\n            { typeof(LightingDataAsset), SubAssetType.LightingDataAsset },\n            { typeof(PhysicsMaterial2D), SubAssetType.PhysicsMaterial2D },\n            { typeof(ShaderVariantCollection), SubAssetType.ShaderVariantCollection },\n            { typeof(TerrainLayer), SubAssetType.TerrainLayer },\n            { typeof(Texture2DArray), SubAssetType.Texture2DArray },\n            { typeof(Texture3D), SubAssetType.Texture3D },\n            { typeof(Cubemap), SubAssetType.Cubemap },\n            { typeof(VideoClip), SubAssetType.VideoClip },\n        };\n\n        // String-based lookup for non-UnityEngine types (Spine, BlendShape, etc.)\n        private static readonly Dictionary<string, SubAssetType> TypeNameToSubAssetType = new Dictionary<string, SubAssetType>\n        {\n            { \"BlendShape\", SubAssetType.BlendShape }, // Internal Unity representation\n            { \"SpineAnimation\", SubAssetType.SpineAnimation }, // Spine-specific\n            { \"SpineSkeletonData\", SubAssetType.SpineSkeletonData }\n        };\n\n        /// <summary>\n        /// Gets the SubAssetType from an object instance.\n        /// </summary>\n        public static SubAssetType GetSubAssetType(Object subAsset)\n        {\n            if (subAsset == null) return SubAssetType.Unknown;\n\n            Type assetType = subAsset.GetType();\n\n            // 1. Check UnityEngine types directly\n            if (TypeToSubAssetType.TryGetValue(assetType, out SubAssetType mappedType))\n            {\n                return mappedType;\n            }\n            \n            // 2. Check if it's a ScriptableObject (catch all ScriptableObjects)\n            if (typeof(ScriptableObject).IsAssignableFrom(assetType))\n            {\n                return SubAssetType.ScriptableObject;\n            }\n\n            // 3. Check by type name (for custom asset types like Spine)\n            return TypeNameToSubAssetType.TryGetValue(assetType.Name, out mappedType)\n                ? mappedType : SubAssetType.Unknown;\n\n        }\n        \n        \n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core/SubAssetDetail.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b50e1e50ed9048598749146f243273c0\ntimeCreated: 1738924564"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Core.meta",
    "content": "fileFormatVersion: 2\nguid: 79e0b652bba84906a634b7dcf189ea7d\ntimeCreated: 1730992920"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderAssetFileDrawer.cs",
    "content": "using System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [CustomPropertyDrawer(typeof(AssetFinderAssetFile))]\n    public class AssetFinderAssetFileDrawer : PropertyDrawer\n    {\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            EditorGUI.BeginProperty(position, label, property);\n            \n            // Get serialized properties\n            var fr2IdProp = property.FindPropertyRelative(\"fr2Id\");\n            var guidProp = property.FindPropertyRelative(\"guid\");\n            var fileIdsProp = property.FindPropertyRelative(\"fileIds\");\n            \n            // Load the asset using the GUID\n            string assetPath = AssetDatabase.GUIDToAssetPath(guidProp.stringValue);\n            // Object asset = AssetDatabase.LoadAssetAtPath<Object>(assetPath);\n\n            // Set fixed widths for AssetFinderID and GUID fields\n            float fr2IdWidth = 70f; \n            float guidWidth = 280f;\n            float spacing = 5f;\n\n            // Draw Asset Path as clickable label at the top\n            Rect assetPathRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);\n            AssetFinderAssetGUI.DrawAsset(assetPathRect, guidProp.stringValue);\n            \n            // Calculate Rects for AssetFinderID and GUID on the same line below the asset path\n            Rect fr2IdRect = new Rect(position.x, assetPathRect.yMax + EditorGUIUtility.standardVerticalSpacing, fr2IdWidth, EditorGUIUtility.singleLineHeight);\n            Rect guidRect = new Rect(fr2IdRect.xMax + spacing, fr2IdRect.y, guidWidth, EditorGUIUtility.singleLineHeight);\n            \n            // Draw GUID button\n            var fr2Id = (AssetFinderID)fr2IdProp.FindPropertyRelative(\"value\").intValue;\n            AssetFinderAssetGUI.DrawId(fr2IdRect, fr2Id);\n            \n            // Draw GUID button\n            AssetFinderAssetGUI.DrawGuid(guidRect, guidProp.stringValue);\n            \n            EditorGUI.indentLevel--;\n            EditorGUI.EndProperty();\n        }\n\n        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)\n        {\n            // Calculate height based on the contents\n            var fileIdsProp = property.FindPropertyRelative(\"fileIds\");\n            float lineHeight = EditorGUIUtility.singleLineHeight;\n            float spacing = EditorGUIUtility.standardVerticalSpacing;\n\n            // Estimate the number of lines required for the fileId buttons\n            float totalWidth = EditorGUIUtility.currentViewWidth;\n            float currentLineWidth = 0;\n            int lineCount = 1; // Start with one line\n\n            for (int i = 0; i < fileIdsProp.arraySize; i++)\n            {\n                string fileIdText = fileIdsProp.GetArrayElementAtIndex(i).longValue.ToString();\n                float buttonWidth = EditorStyles.label.CalcSize(new GUIContent(fileIdText)).x + 8f;\n\n                if (currentLineWidth + buttonWidth > totalWidth)\n                {\n                    lineCount++;\n                    currentLineWidth = buttonWidth;\n                }\n                else\n                {\n                    currentLineWidth += buttonWidth + spacing;\n                }\n            }\n\n            return lineHeight * (4 + lineCount) + spacing * 3 + 8f;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderAssetFileDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9d0464c486a72c145a862aaf1ec01dbb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderCacheAssetEditor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [CustomEditor(typeof(AssetFinderCacheAsset))]\n    internal class AssetFinderCacheAssetEditor : UnityEditor.Editor\n    {\n        private FileUI fileUI;\n        private AssetFinderAssetFile file;\n        private readonly List<AssetFinderIDRef> fileUsage = new List<AssetFinderIDRef>();\n        private readonly List<AssetRefUI> usages = new List<AssetRefUI>();\n\n        public override void OnInspectorGUI()\n        {\n            base.OnInspectorGUI();\n\n            if (file == null) return;\n\n            Rect rect = EditorGUILayout.GetControlRect();\n            if (fileUI == null) fileUI = AssetUI.Get<FileUI>(file.guid, true);\n            if (fileUI == null) return; // Invalid FileUI\n\n            var result = rect.ExtractRight(50f);\n            var lbRect = result.Item1;\n            var r = result.Item2;\n            GUI.Label(lbRect, $\"({usages.Count})\", EditorStyles.miniLabel);\n\n            var r1 = rect;\n            fileUI.DrawAsset(ref r1, true, false);\n            \n            rect.xMin += 18f;\n            rect.y += 18f;\n            for (var i = 0; i < usages.Count; i++)\n            {\n                var item = usages[i];\n                item.Draw(ref rect);\n            }\n        }\n\n        private void OnEnable()\n        {\n            Selection.selectionChanged -= OnChangeSelection;\n            Selection.selectionChanged += OnChangeSelection;\n        }\n\n        void OnChangeSelection()\n        {\n            if (!AssetFinderCacheAsset.isReady) return;\n\n            var obj = Selection.activeObject;\n            if (obj == null) return;\n\n            if (!EditorUtility.IsPersistent(obj))\n            {\n                // Unsupported: SceneObject\n                return;\n            }\n\n            if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out string guid, out long localId))\n            {\n                return;\n            }\n\n            file = AssetFinderCacheAsset.GetFile(guid);\n            \n            fileUsage.Clear();\n            AssetFinderCacheAsset.CollectUsage(guid, fileUsage);\n            \n            usages.Clear();\n            usages.AddRange(fileUsage\n                .Select(item => AssetFinderCacheAsset.GetGuidAndFileId(item.toId))\n                .Select(item =>\n                {\n                    AssetFinderAssetFile asset = AssetFinderCacheAsset.GetFile(item.guid);\n                    asset.LoadAllSubAssetsIfNeeded();\n                    return item;\n                })\n                .GroupBy(item => item.guid)\n                \n                .Select(g => new AssetRefUI(\n                    g.Key, AssetDatabase.GUIDToAssetPath(g.Key),\n                    g.Select(item => item.fileId).ToList())));\n            \n            GC.Collect();\n            Resources.UnloadUnusedAssets();\n            Repaint();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderCacheAssetEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6748e1a1e91d4094286862d7c9aea483\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderIDDrawer.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    [CustomPropertyDrawer(typeof(AssetFinderID))]\n    public class AssetFinderIDDrawer : PropertyDrawer\n    {\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            // Get the 'value' field in the serialized property\n            var valueProp = property.FindPropertyRelative(\"value\");\n            var assetIndex = (valueProp.intValue >> 10) & 0x3FFFFF;\n            var subAssetIndex = valueProp.intValue & 0x3FF;\n\n            // Set the button content with assetIndex and subAssetIndex, and show value as tooltip\n            GUIContent buttonContent = AssetFinderGUIContent.FromString($\"[{assetIndex} : {subAssetIndex}]\", $\"Value: {valueProp.intValue}\");\n            GUI.Label(position, buttonContent);\n            \n            // EditorGUIUtility.systemCopyBuffer = valueProp.intValue.ToString();\n            // Debug.Log(\"Copied Value: \" + EditorGUIUtility.systemCopyBuffer);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer/AssetFinderIDDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ccc51a6989160944688a10eb95b36fcd\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Drawer.meta",
    "content": "fileFormatVersion: 2\nguid: c5ef076df01604f89987b1c1701a11bd\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetGUI.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public static class AssetFinderAssetGUI\n    {\n        public class DrawContext\n        {\n            public bool drawPath = false;\n            public bool drawHighlight = true;\n        }\n        \n        // draw context\n        public static DrawContext context = new DrawContext();\n        \n        public static void DrawAsset(Rect rect, AssetFinderID id)\n        {\n            var assetFR2Id = id.WithoutSubAssetIndex();\n            var (guid, _) = AssetFinderCacheAsset.GetGuidAndFileId(assetFR2Id);\n            DrawAsset(rect, guid);\n        }\n\n        public static void DrawId(Rect rect, AssetFinderID fr2Id)\n        {\n            var fr2IdWidth = 70f;\n            int assetIndex = fr2Id.AssetIndex;\n            int subIndex = fr2Id.SubAssetIndex;\n            GUIContent title = AssetFinderGUIContent.FromString($\"[{assetIndex}-{subIndex}]\", $\"Value: {fr2Id}\");\n            \n            if (GUI.Button(GUI2.LeftRect(fr2IdWidth, ref rect), title))\n            {\n                EditorGUIUtility.systemCopyBuffer = fr2Id.ToString();\n                UnityEngine.Debug.Log(\"Copied AssetFinderID Value: \" + EditorGUIUtility.systemCopyBuffer);\n            }\n        }\n        \n        public static void DrawGuid(Rect rect, string guid)\n        {\n            var fr2IdWidth = 250f;\n            GUIContent title = AssetFinderGUIContent.FromString(guid, \"Click to copy GUID\");\n            if (GUI.Button(GUI2.LeftRect(fr2IdWidth, ref rect), title))\n            {\n                EditorGUIUtility.systemCopyBuffer = guid;\n                AssetFinderLOG.Log(\"Copied AssetFinderID Value: \" + EditorGUIUtility.systemCopyBuffer);\n            }\n        }\n        \n        public static void DrawAsset(Rect rect, string guid)\n        {\n            var info = AssetFinderAssetInfo.GetOrCreate(guid);\n            if (info.folderContent == null) info.RefreshGUIContent();\n\n            float pathW = context.drawPath ? EditorStyles.miniLabel.CalcSize(info.folderContent).x\n                : 8f;\n\n            float nameW = context.drawPath\n                ? EditorStyles.boldLabel.CalcSize(info.fileNameContent).x\n                : EditorStyles.label.CalcSize(info.fileNameContent).x;\n\n            float extW = string.IsNullOrEmpty(info.fileExt)\n                ? 0f\n                : EditorStyles.miniLabel.CalcSize(info.fileExtContent).x;\n            \n            \n            Rect iconRect = GUI2.LeftRect(16f, ref rect);\n            if (Event.current.type == EventType.Repaint)\n            {\n                Texture icon = AssetDatabase.GetCachedIcon(info.assetPath);\n                if (icon != null) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit);\n            }\n            \n            if (context.drawPath)\n            {\n                Color c2 = GUI.color;\n                GUI.color = new Color(c2.r, c2.g, c2.b, c2.a * 0.5f);\n                GUI.Label(GUI2.LeftRect(pathW, ref rect), info.folderContent, EditorStyles.miniLabel);\n                GUI.color = c2;\n                rect.xMin -= 2f;\n            }\n            \n            \n            GUI.Label(GUI2.LeftRect(nameW, ref rect), info.fileNameContent,\n                context.drawPath ? EditorStyles.boldLabel : EditorStyles.label);\n            \n            if (extW > 0)\n            {\n                rect.xMin -= 2f;\n                GUI.Label(GUI2.LeftRect(extW, ref rect), info.fileExtContent, EditorStyles.miniLabel);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetGUI.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ce2370394863b3a4e8defddcd3099ac5\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetInfo.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public class AssetFinderAssetInfo\n    {\n        [NonSerialized] internal static readonly Dictionary<string, AssetFinderAssetInfo> infoMap = new Dictionary<string, AssetFinderAssetInfo>();\n        \n        internal static AssetFinderAssetInfo Get(string guid) => infoMap.GetValueOrDefault(guid);\n        internal static AssetFinderAssetInfo GetOrCreate(string guid) => infoMap.GetValueOrDefault(guid) ?? new AssetFinderAssetInfo(guid);\n        internal static void Clear() => infoMap.Clear();\n        \n        public string guid;\n        public string assetPath;\n\n        public string folder;\n        public string fileName;\n        public string fileExt;\n\n        // GUIContent\n        public GUIContent folderContent;\n        public GUIContent fileNameContent;\n        public GUIContent fileExtContent;\n\n        private AssetFinderAssetInfo(string guid)\n        {\n            this.guid = guid;\n            assetPath = AssetDatabase.GUIDToAssetPath(guid);\n            folder = System.IO.Path.GetDirectoryName(assetPath) + \"/\";\n            fileName = System.IO.Path.GetFileNameWithoutExtension(assetPath);\n            fileExt = System.IO.Path.GetExtension(assetPath);\n\n            infoMap.Add(guid, this);\n        }\n\n        public void RefreshGUIContent()\n        {\n            folderContent = AssetFinderGUIContent.From(folder);\n            fileNameContent = AssetFinderGUIContent.From(fileName);\n            fileExtContent = string.IsNullOrEmpty(fileExt) ? GUIContent.none : AssetFinderGUIContent.From(fileExt);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/GUI/AssetFinderAssetInfo.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 74f0b16f4b79c4b4cabbb09c38ddc794\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/GUI.meta",
    "content": "fileFormatVersion: 2\nguid: 59606708556974356adfa65945cc7c11\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.BinaryAsset.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEngine;\nusing UnityEditor;\n\nusing UnityObject = UnityEngine.Object;\nusing AddUsageCB = System.Action<string, long>;\n\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // BinaryAsset\n    {\n        private static HashSet<string> BINARY_ASSET = new HashSet<string>()\n        {\n            \".asset\", \".spriteatlas\", \".unity\"\n        };\n        \n        private static bool Read_VerifyBinaryAsset(string assetPath)\n        {\n            try\n            {\n                foreach (string line in File.ReadLines(assetPath))\n                {\n                    return !line.StartsWith(\"%YAML\", StringComparison.Ordinal);\n                }\n            } catch (Exception e)\n            {\n                LogWarning($\"Read_VerifyBinaryAsset error: {assetPath}\\n{e}\");\n            }\n\n            // Should never be here!\n            return false;\n        }\n        \n        private static void ReadContent_BinaryAsset(string filePath, AddUsageCB callback)\n        {\n            string ext = Path.GetExtension(filePath).ToLowerInvariant();\n            if (!BINARY_ASSET.Contains(ext)) return;\n            \n            var allAssets = AssetDatabase.LoadAllAssetsAtPath(filePath);\n            foreach (UnityObject assetData in allAssets)\n            {\n                LogWarning($\"Asset: {assetData} : {assetData.GetType()}\");\n                \n                if (assetData is GameObject go)\n                {\n                    Component[] compList = go.GetComponentsInChildren<Component>(true);\n                    for (var i = 0; i < compList.Length; i++)\n                    {\n                        LoadSerialized(compList[i], callback);\n                    }\n                }\n                else if (assetData is TerrainData terrainData)\n                {\n                    Read_TerrainData(terrainData, callback);\n                }\n                else if (assetData is LightingDataAsset lightingDataAsset)\n                {\n                    Read_LightMap(lightingDataAsset, callback);\n                }\n                else\n                {\n                    LoadSerialized(assetData, callback);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.BinaryAsset.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 118795563d36de44a8d02c8399654aec\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.LightMap.cs",
    "content": "using UnityEditor;\nusing AddUsageCB = System.Action<string, long>;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // LightMap\n    {\n        // BWCompatible\n        internal static void LoadLightingData(this AssetFinderAsset asset, LightingDataAsset data)\n        {\n            Read_LightMap(data, (guid, fileId) => asset.AddUseGUID(guid, fileId));\n        }\n        \n        private static void Read_LightMap(LightingDataAsset asset, AddUsageCB callback)\n        {\n            if (asset == null) return;\n            foreach (var texture in AssetFinderLightmap.Read(asset))\n            {\n                AddObjectUsage(texture, callback);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.LightMap.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 63fe5cc863d036d43a50260f5365edd7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Model3D.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityObject = UnityEngine.Object;\nusing AddUsageCB = System.Action<string, long>;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // Model3D\n    {\n        private static readonly HashSet<string> MODEL_FILES = new HashSet<string>()\n        {\n            \".fbx\", \".obj\", \".3ds\", \".dxf\", \".max\", \".c4d\", \".blend\", \n            \".lwo\", \".lws\", \".ma\", \".mb\", \".jas\", \".skp\", \".dae\", \".3dm\", \n            \".stl\", \".ply\", \".dxf\", \".lwo\", \".lws\"\n        };\n\n        private static void Read_Model3D(GameObject go, AddUsageCB callback)\n        {\n            Component[] compList = go.GetComponentsInChildren<Component>();\n            for (var i = 0; i < compList.Length; i++)\n            {\n                LoadSerialized(compList[i], callback);\n            }\n        }\n        \n        private static void LoadSerialized(UnityObject target, AddUsageCB callback)\n        {\n            SerializedProperty[] props = AssetFinderUnity.xGetSerializedProperties(target, true);\n\n            for (var i = 0; i < props.Length; i++)\n            {\n                if (props[i].propertyType != SerializedPropertyType.ObjectReference) continue;\n                UnityObject refObj = props[i].objectReferenceValue;\n                AddObjectUsage(refObj, callback);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Model3D.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1d35288c86839146b50b9e6c2963c62\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Shader.cs",
    "content": "using System;\nusing System.Text.RegularExpressions;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // Shader\n    {\n        private static void ReadContent_Shader(string filePath, Action<string, long> callback)\n        {\n            Log($\"[FR2] Reading shader file: {filePath}\");\n            Read(filePath, ParseLine_Shader, callback, false); // Don't use double-check for shader files\n        }\n\n        private static (string guid, long fileId) ParseLine_Shader(string line)\n        {\n#if AssetFinderDEV\n            if (line.TrimStart().StartsWith(\"#include\"))\n            {\n                Log($\"[FR2] Processing include line: {line.Trim()}\");\n            }\n#endif\n            \n            // Pattern 1: #include directives with quotes\n            // Example: #include \"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl\"\n            if (line.TrimStart().StartsWith(\"#include\"))\n            {\n                string includePath = Find(line, \"#include \\\"\", \"\\\"\");\n                Log($\"[FR2] Found quoted include path: '{includePath}'\");\n                if (!string.IsNullOrEmpty(includePath))\n                {\n                    string resolvedPath = ResolveShaderIncludePath(includePath);\n                    Log($\"[FR2] Resolved path: '{resolvedPath}'\");\n                    if (!string.IsNullOrEmpty(resolvedPath))\n                    {\n                        string guid = UnityEditor.AssetDatabase.AssetPathToGUID(resolvedPath);\n                        Log($\"[FR2] Path to GUID: '{resolvedPath}' -> '{guid}'\");\n                        if (!string.IsNullOrEmpty(guid))\n                        {\n                            Log($\"[FR2] SUCCESS - Shader Include: {includePath} -> {resolvedPath} -> {guid}\");\n                            return (guid, -1);\n                        }\n                    }\n                }\n            }\n\n            // Pattern 2: #include directives with angle brackets  \n            // Example: #include <HLSLSupport.cginc>\n            if (line.TrimStart().StartsWith(\"#include\"))\n            {\n                string includePath = Find(line, \"#include <\", \">\");\n                if (!string.IsNullOrEmpty(includePath))\n                {\n                    string resolvedPath = ResolveShaderIncludePath(includePath);\n                    if (!string.IsNullOrEmpty(resolvedPath))\n                    {\n                        string guid = UnityEditor.AssetDatabase.AssetPathToGUID(resolvedPath);\n                        if (!string.IsNullOrEmpty(guid))\n                        {\n                            Log($\"[FR2] Shader Include: {includePath} -> {resolvedPath} -> {guid}\");\n                            return (guid, -1);\n                        }\n                    }\n                }\n            }\n\n            return (null, -1);\n        }\n\n        private static string ResolveShaderIncludePath(string includePath)\n        {\n            if (string.IsNullOrEmpty(includePath)) return null;\n\n            Log($\"[FR2] Resolving shader include path: '{includePath}'\");\n\n            // Pattern 1: Packages/ references\n            // Example: \"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl\"\n            if (includePath.StartsWith(\"Packages/\"))\n            {\n                // Check if the path exists directly\n                if (System.IO.File.Exists(includePath))\n                {\n                    Log($\"[FR2] Found direct package path: {includePath}\");\n                    return includePath;\n                }\n            }\n\n            // Pattern 2: Relative paths from project\n            // Example: \"Assets/Shaders/Common.hlsl\"\n            if (includePath.StartsWith(\"Assets/\"))\n            {\n                if (System.IO.File.Exists(includePath))\n                {\n                    return includePath;\n                }\n            }\n\n            // Pattern 3: Search in common Unity shader include directories\n            string[] searchDirectories = {\n                \"Assets/\",\n                \"Assets/Shaders/\",\n                \"Assets/Scripts/Shaders/\",\n                \"Packages/com.unity.render-pipelines.core/ShaderLibrary/\",\n                \"Packages/com.unity.render-pipelines.universal/ShaderLibrary/\",\n                \"Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/\",\n                \"Packages/com.unity.shadergraph/ShaderGraphLibrary/\"\n            };\n\n            foreach (string searchDir in searchDirectories)\n            {\n                string fullPath = searchDir + includePath;\n                if (System.IO.File.Exists(fullPath))\n                {\n                    return fullPath;\n                }\n\n                // Also try without directory structure (flat search)\n                string fileName = System.IO.Path.GetFileName(includePath);\n                string flatPath = searchDir + fileName;\n                if (System.IO.File.Exists(flatPath))\n                {\n                    return flatPath;\n                }\n            }\n\n            // Pattern 4: Search using Unity's AssetDatabase for filename matches\n            string targetFileName = System.IO.Path.GetFileNameWithoutExtension(includePath);\n            string targetExtension = System.IO.Path.GetExtension(includePath);\n            \n            if (string.IsNullOrEmpty(targetExtension))\n            {\n                // Try common shader extensions if no extension provided\n                string[] extensions = { \".hlsl\", \".cginc\", \".shader\", \".glsl\" };\n                foreach (string ext in extensions)\n                {\n                    string[] matchingGuids = UnityEditor.AssetDatabase.FindAssets($\"{targetFileName} t:DefaultAsset\");\n                    foreach (string guid in matchingGuids)\n                    {\n                        string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);\n                        if (assetPath.EndsWith(ext) && System.IO.Path.GetFileNameWithoutExtension(assetPath) == targetFileName)\n                        {\n                            return assetPath;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                // Search for exact filename match\n                string[] matchingGuids = UnityEditor.AssetDatabase.FindAssets($\"{targetFileName} t:DefaultAsset\");\n                foreach (string guid in matchingGuids)\n                {\n                    string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);\n                    if (System.IO.Path.GetFileName(assetPath).Equals(System.IO.Path.GetFileName(includePath), StringComparison.OrdinalIgnoreCase))\n                    {\n                        return assetPath;\n                    }\n                }\n            }\n\n            return null;\n        }\n    }\n} "
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Shader.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 933793502ca2eb2499dc3b6bc25a4dc4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.ShaderGraph.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // ShaderGraph\n    {\n        private static readonly Dictionary<string, Func<string, (string, long)>> SHADER_GRAPH_FILES\n            = new Dictionary<string, Func<string, (string, long)>>()\n            {\n                { \".shadergraph\", ParseLine_Json },\n                { \".shadersubgraph\", ParseLine_Json },\n            };\n\n        private static void ReadContent_ShaderGraph(string ext, string assetPath, Action<string, long> callback)\n        {\n            Func<string, (string, long)> lineParser = SHADER_GRAPH_FILES[ext];\n            Read(assetPath, lineParser, callback);\n        }\n\n        private static (string guid, long fileId) ParseLine_Json(string line)\n        {\n            string guid = Find(line, \"\\\\\\\"guid\\\\\\\":\\\\\\\"\", \"\\\\\\\",\");\n            if (string.IsNullOrEmpty(guid)) return (null, -1);\n\n            string fileIdStr = Find(line, \"\\\"fileID\\\\\\\":\", \",\");\n            if (string.IsNullOrEmpty(fileIdStr)) return (null, -1);\n\n            if (!long.TryParse(fileIdStr, out long fileId)) fileId = -1;\n            return (guid, fileId);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.ShaderGraph.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a30b788b96d832b41bcada6c0eaffa99\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Terrain.cs",
    "content": "using System;\nusing UnityEngine;\nusing UnityEditor;\nusing AddUsageCB = System.Action<string, long>;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // Terrain\n    {\n        // BWCompatible\n        internal static void LoadTerrainData(this AssetFinderAsset asset, TerrainData data)\n        {\n            Read_TerrainData(data, (string guid, long fileId) => asset.AddUseGUID(guid, fileId));\n        }\n        \n        private static void Read_TerrainData(TerrainData terrain, AddUsageCB callback)\n        {\n#if UNITY_2018_3_OR_NEWER\n            TerrainLayer[] layers = terrain.terrainLayers;\n            for (var i = 0; i < layers.Length; i++)\n            {\n                AddObjectUsage(layers[i], callback);\n            }\n#endif\n            DetailPrototype[] details = terrain.detailPrototypes;\n            for (var i = 0; i < details.Length; i++)\n            {\n                AddObjectUsage(details[i].prototypeTexture, callback);\n            }\n\n            TreePrototype[] trees = terrain.treePrototypes;\n            for (var i = 0; i < trees.Length; i++)\n            {\n                AddObjectUsage(trees[i].prefab, callback);\n            }\n            \n            AssetFinderTerrain.TerrainTextureData[] texDatas = AssetFinderTerrain.GetTerrainTextureDatas(terrain);\n            for (var i = 0; i < texDatas.Length; i++)\n            {\n                AssetFinderTerrain.TerrainTextureData texs = texDatas[i];\n                for (var k = 0; k < texs.textures.Length; k++)\n                {\n                    Texture2D tex = texs.textures[k];\n                    if (tex == null) continue;\n\n                    AssetDatabase.TryGetGUIDAndLocalFileIdentifier(tex, out string refGUID, out long fileId);\n                    callback(refGUID, fileId);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Terrain.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c29120f806f185647b4021d77b976629\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.UIToolkit.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // UIToolkit\n    {\n        private static readonly Dictionary<string, Func<string, (string, long)>> UI_TOOLKIT_FILES\n            = new Dictionary<string, Func<string, (string, long)>>()\n            {\n                {\".tss\", ParseLine_Tss},\n                {\".uxml\", ParseLine_Uxml_Uss},\n                {\".uss\", ParseLine_Uxml_Uss}\n            };\n\n        private static void ReadContent_UIToolkit(string ext, string assetPath, Action<string, long> callback)\n        {\n            Func<string, (string, long)> lineParser = UI_TOOLKIT_FILES[ext];\n            Read(assetPath, lineParser, callback);\n        }\n        \n        private static (string guid, long fileId) ParseLine_Uxml_Uss(string line)\n        {\n            // Check for traditional GUID references first\n            var result = FindRef(line, \"guid=\", \"fileID=\", \"&\");\n            if (result.guid != null) return result;\n            \n            // Handle UXML Style src references with project://database/ URIs\n            if (line.Contains(\"<Style\") && line.Contains(\"src=\"))\n            {\n                string srcPath = Find(line, \"src=\\\"\", \"\\\"\");\n                if (!string.IsNullOrEmpty(srcPath))\n                {\n                    string resolvedPath = ResolveProjectDatabasePath(srcPath);\n                    if (!string.IsNullOrEmpty(resolvedPath))\n                    {\n                        string guid = AssetDatabase.AssetPathToGUID(resolvedPath);\n                        if (!string.IsNullOrEmpty(guid))\n                        {\n                            // AssetFinderLOG.Log($\"[FR2] UXML->USS: {srcPath} -> {resolvedPath} -> {guid}\");\n                            return (guid, -1);\n                        }\n                    }\n                    else\n                    {\n                        AssetFinderLOG.LogWarning($\"[FR2] Failed to resolve UXML Style src: {srcPath}\");\n                    }\n                }\n            }\n            \n            // Handle resource() references for USS files\n            if (line.Contains(\"resource(\"))\n            {\n                string resourcePath = Find(line, \"resource(\\\"\", \"\\\")\");\n                if (string.IsNullOrEmpty(resourcePath))\n                {\n                    resourcePath = Find(line, \"resource('\", \"')\");\n                }\n                \n                if (!string.IsNullOrEmpty(resourcePath))\n                {\n                    // Unity resource paths can be relative to various locations\n                    string guid = ResolveResourcePath(resourcePath);\n                    if (!string.IsNullOrEmpty(guid))\n                    {\n                        return (guid, -1);\n                    }\n                }\n            }\n            \n            // Handle @import \"\"; references for USS files : @import \"Base.uss\";\n            if (line.Contains(\"@import\"))\n            {\n                string importPath = Find(line, \"@import \\\"\", \"\\\";\");\n                if (string.IsNullOrEmpty(importPath))\n                {\n                    importPath = Find(line, \"@import '\", \"';\");\n                }\n                \n                \n                if (!string.IsNullOrEmpty(importPath))\n                {\n                    // Unity resource paths can be relative to various locations\n                    string resolvedPath = ResolveProjectDatabasePath(importPath);\n                    if (!string.IsNullOrEmpty(resolvedPath))\n                    {\n                        string guid = AssetDatabase.AssetPathToGUID(resolvedPath);\n                        if (!string.IsNullOrEmpty(guid))\n                        {\n                            // AssetFinderLOG.Log($\"[FR2] USS->USS: {importPath} -> {resolvedPath} -> {guid}\");\n                            return (guid, -1);\n                        }\n                    }\n                    else\n                    {\n                        AssetFinderLOG.LogWarning($\"[FR2] Failed to resolve USS import: {importPath}\");\n                    }\n                }\n            }\n            \n            return (null, -1);\n        }\n        \n        private static string ResolveProjectDatabasePath(string path)\n        {\n            // Handle project://database/ URIs\n            if (path.StartsWith(\"project://database/\"))\n            {\n                // Remove the project://database/ prefix to get the actual asset path\n                string assetPath = path.Substring(\"project://database/\".Length);\n                \n                // Check if this path exists in the project\n                if (System.IO.File.Exists(assetPath))\n                {\n                    return assetPath;\n                }\n            }\n            \n            // full path\n            if (System.IO.File.Exists(path)) return path;\n            \n            // relative path\n            var folder = parsingFilePath.Substring(0, parsingFilePath.LastIndexOf('/'));\n            var fullRelativePath = Path.Combine(folder, path);\n            if (System.IO.File.Exists(fullRelativePath))\n            {\n                return fullRelativePath;\n            }\n            \n            return null;\n        }\n        \n        private static string ResolveResourcePath(string resourcePath)\n        {\n            // Common Unity resource locations to search\n            string[] searchPaths = {\n                $\"Assets/Editor Default Resources/{resourcePath}\",\n                $\"Assets/Resources/{resourcePath}\",\n                $\"Assets/{resourcePath}\",\n                resourcePath\n            };\n            \n            foreach (string searchPath in searchPaths)\n            {\n                if (System.IO.File.Exists(searchPath))\n                {\n                    return AssetDatabase.AssetPathToGUID(searchPath);\n                }\n            }\n            \n            // Check in all package locations\n            string[] packageGuids = AssetDatabase.FindAssets($\"t:DefaultAsset {System.IO.Path.GetFileNameWithoutExtension(resourcePath)}\");\n            foreach (string guid in packageGuids)\n            {\n                string path = AssetDatabase.GUIDToAssetPath(guid);\n                if (path.EndsWith(resourcePath))\n                {\n                    return guid;\n                }\n            }\n            \n            return null;\n        }\n\n        private static (string guid, long fileId) ParseLine_Tss(string line)\n        {\n            string assetPath = Find(line, \"@importurl(\\\"/\", \"\\\")\");\n            return string.IsNullOrEmpty(assetPath)\n                ? (null, -1)\n                : (AssetDatabase.AssetPathToGUID(assetPath), 0);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.UIToolkit.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ab428f706dd08db41981186820926948\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Yaml.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal static partial class AssetFinderParser // Yaml\n    {\n        private static readonly HashSet<string> YAML_FILES = new HashSet<string>()\n        {\n            \".anim\", \".controller\", \".mat\", \".unity\", \".guiskin\", \".prefab\", \n            \".overridecontroller\", \".mask\", \".rendertexture\", \".cubemap\", \".flare\", \n            \".playable\", \".physicsmaterial\", \".fontsettings\", \".asset\", \".prefs\", \n            \".spriteatlas\", \".terrainlayer\", \".asmdef\", \".preset\", \".spriteLib\", \".texture2darray\"\n        };\n        \n        \n        private static void ReadContent_YAML(string filePath, Action<string, long> callback)\n        {\n            string ext = Path.GetExtension(filePath).ToLowerInvariant();\n            bool isBinary = BINARY_ASSET.Contains(ext) && Read_VerifyBinaryAsset(filePath);\n\n            if (isBinary)\n            {\n                ReadContent_BinaryAsset(filePath, callback);\n            } else\n            {\n                Read(filePath, ParseLine_Yaml, callback);    \n            }\n        }\n        \n        private static (string guid, long fileId) ParseLine_Yaml(string line)\n        {\n            // Check for both 'guid:' and 'm_AssetGUID:' patterns\n            (string guid, long fileId) result = FindRef(line, \"guid:\", \"fileID:\", \",\");\n            if (result.guid != null) return result;\n            result = FindRef(line, \"m_AssetGUID:\", null, null);\n            return string.IsNullOrEmpty(result.guid) \n                ? FindRef(line, \"GUID:\", null, null)\n                : result;\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.Yaml.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fb684659a7b55c84c9de5867ca66c64e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.cs",
    "content": "// #define AssetFinderPARSER_DEBUG\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\nusing UnityEditor;\nusing UnityEngine;\nusing AddUsageCB = System.Action<string, long>;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    // Public APIs\n    internal static partial class AssetFinderParser \n    {\n        private static readonly HashSet<string> META_FILES = new HashSet<string>()\n        {\n            \".texture2darray\",\".png\", \".jpg\", \".jpeg\", \".tga\", \".tif\", \".tiff\", \".psd\", \".bmp\", \".exr\", \".gif\",\n            \n            // Support static references\n            \".shader\", \".cs\",\n            \n            // Custom importers\n            \".shadergraph\"\n        };\n        \n        private static readonly HashSet<string> SHADER_FILES = new HashSet<string>()\n        {\n            \".shader\", \".hlsl\", \".cginc\", \".glsl\"\n        };\n        \n        public static bool IsReadable(string assetPath)\n        {\n            string ext = Path.GetExtension(assetPath).ToLowerInvariant();\n            return IsReadableExtension(ext);\n        }\n        public static bool IsReadableExtension(string ext)\n        {\n            return YAML_FILES.Contains(ext) \n                || UI_TOOLKIT_FILES.ContainsKey(ext)\n                || SHADER_GRAPH_FILES.ContainsKey(ext)\n                || META_FILES.Contains(ext)\n                || SHADER_FILES.Contains(ext);\n        }\n\n        [Conditional(\"AssetFinderPARSER_DEBUG\")]\n        public static void LogWarning(string message, UnityEngine.Object target = null)\n            => UnityEngine.Debug.LogWarning(message, target);\n        \n        [Conditional(\"AssetFinderPARSER_DEBUG\")]\n        public static void Log(string message, UnityEngine.Object target = null)\n            => UnityEngine.Debug.Log(message, target);\n        \n        public static void ReadContent(string filePath, AddUsageCB callback)\n        {\n            string ext = Path.GetExtension(filePath).ToLowerInvariant();\n            bool readMeta = META_FILES.Contains(ext);\n            if (readMeta) // Also need to read .meta file\n            {\n                ReadContent_YAML(filePath + \".meta\", callback);\n            }\n            \n            if (YAML_FILES.Contains(ext))\n            {\n                ReadContent_YAML(filePath, callback); \n                return;\n            }\n            \n            if (SHADER_GRAPH_FILES.ContainsKey(ext))\n            {\n                ReadContent_ShaderGraph(ext, filePath, callback);\n                return;\n            }\n\n            if (UI_TOOLKIT_FILES.ContainsKey(ext))\n            {\n                ReadContent_UIToolkit(ext, filePath, callback);\n                return;\n            }\n            \n            if (SHADER_FILES.Contains(ext))\n            {\n                // TODO: VALIDATE\n                // ReadContent_Shader(filePath, callback);\n                return;\n            }\n            \n            if (!readMeta) LogWarning(\"Unknown file type: \" + filePath);\n        }\n    }\n    \n    \n    internal static partial class AssetFinderParser\n    {\n        private static string parsingFilePath;\n        private static void AddObjectUsage(UnityEngine.Object refObj, AddUsageCB callback)\n        {\n            if (refObj == null) return;\n            if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(refObj, out string refGUID, out long fileId))\n            {\n                callback(refGUID, fileId);\n            }\n        }\n\n        private static void Read(string filePath, Func<string, (string, long)> lineHandler, Action<string, long> add, bool doubleCheck = true)\n        {\n            if (!File.Exists(filePath)) return;\n\n            parsingFilePath = filePath;\n            \n            // Use a buffer to reduce file I/O overhead\n            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096))\n            using (var sr = new StreamReader(fs, Encoding.UTF8, false, 4096))\n            {\n                string line;\n\n                while ((line = sr.ReadLine()) != null)\n                {\n                    if (string.IsNullOrEmpty(line)) continue;\n\n                    var (guid, fileId) = lineHandler(line);\n                    if (!string.IsNullOrEmpty(guid))\n                    {\n                        add(guid, fileId);\n\n                        // Debug.Log($\"Found: <{guid}:{fileId}>\");\n                        continue;\n                    }\n\n                    if (!doubleCheck) continue;\n                    guid = ExtractGuid(line);\n                    if (!string.IsNullOrEmpty(guid))\n                    {\n                        LogWarning($\"Missed GUID <{guid}>?\\n{filePath}\\n{line}\\n\");\n                        add(guid, 0);\n                    }\n                }\n            }\n        }\n\n        private static string ExtractGuid(string line)\n        {\n            const int GuidLength = 32;\n            var validCharCount = 0;\n\n            for (var i = 0; i < line.Length; i++)\n            {\n                // Check if the character is a valid hex character (0-9, a-f, A-F)\n                if (IsHexChar(line[i]))\n                {\n                    validCharCount++;\n\n                    if (validCharCount == GuidLength)\n                    {\n                        // Return substring from the start of the valid sequence\n                        return line.Substring(i - GuidLength + 1, GuidLength);\n                    }\n                } else\n                {\n                    // Reset count if a non-hex character interrupts the sequence\n                    validCharCount = 0;\n                }\n            }\n\n            return null; // No valid GUID found\n        }\n\n        // Helper method to check if a character is a hex character\n        private static bool IsHexChar(char c)\n        {\n            return ((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));\n        }\n        \n        \n        \n        private static (string guid, long fileId) FindRef(string source, string guidPattern, string fileIdPattern, string separatorPattern)\n        {\n            string guid = Find(source, guidPattern, separatorPattern);\n            if (string.IsNullOrEmpty(guid)) return (null, -1);\n\n            if (string.IsNullOrEmpty(fileIdPattern)) return (guid, -1);\n            string fileIdStr = Find(source, fileIdPattern, separatorPattern);\n            if (string.IsNullOrEmpty(fileIdStr)) return (null, -1);\n\n            if (!long.TryParse(fileIdStr, out long fileId)) fileId = -1;\n\n            // Debug.Log($\"Found: {guid}/{fileId}\\t\\t {source}\");\n            return (guid, fileId);\n        }\n\n        private static string Find(string source, string str_begin, string str_end)\n        {\n            int st = source.IndexOf(str_begin, StringComparison.Ordinal);\n            if (st == -1) return null;\n            st += str_begin.Length;\n            while (st < source.Length && char.IsWhiteSpace(source[st]))\n            {\n                st++;\n            }\n            \n            if (string.IsNullOrEmpty(str_end)) // no end: determine by length\n            {\n                // Check if we have enough characters left for a valid GUID (32 characters)\n                int remainingLength = source.Length - st;\n                if (remainingLength < 32) return null; // Not enough characters for a valid GUID\n                \n                return source.Substring(st, 32);\n            }\n\n            int ed = source.IndexOf(str_end, st, StringComparison.Ordinal);\n            if (ed == -1) return null;\n            while (ed > st && char.IsWhiteSpace(source[ed - 1]))\n            {\n                ed--;\n            }\n            return source.Substring(st, ed - st);\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser/AssetFinderParser.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 66a97d939b2702e438522fd09b5d5a1f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Parser.meta",
    "content": "fileFormatVersion: 2\nguid: 2aa94c45360ab429f954c2adc286a124\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/AssetRefUI.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class AssetRefUI : FileUI\n    {\n        private static Dictionary<SubAssetType, Texture2D> SubAssetIcons;\n        private Texture2D GetIcon(SubAssetType subType)\n        {\n            if (subType == SubAssetType.Unknown) return null;\n            if (SubAssetIcons == null) CacheIcon();\n            return SubAssetIcons.GetValueOrDefault(subType);\n        }\n        \n        /// <summary>\n        /// Caches icons for different SubAssetTypes using Unity’s internal icon system.\n        /// </summary>\n        public static void CacheIcon()\n        {\n            SubAssetIcons = new Dictionary<SubAssetType, Texture2D>\n            {\n                [SubAssetType.Sprite] = LoadIcon(\"d_Texture Icon\"),\n                [SubAssetType.Mesh] = LoadIcon(\"d_Mesh Icon\"),\n                [SubAssetType.AnimationClip] = LoadIcon(\"d_AnimationClip Icon\"),\n                [SubAssetType.Avatar] = LoadIcon(\"d_Avatar Icon\"),\n                [SubAssetType.Material] = LoadIcon(\"d_Material Icon\"),\n                [SubAssetType.AudioMixerSnapshot] = LoadIcon(\"d_AudioMixerController Icon\"),\n                [SubAssetType.LightingDataAsset] = LoadIcon(\"LightingDataAsset Icon\", \"LightProbeGroup Icon\"),\n                [SubAssetType.ScriptableObject] = LoadIcon(\"d_ScriptableObject Icon\"),\n                [SubAssetType.ShaderVariantCollection] = LoadIcon(\"d_Shader Icon\"),\n                [SubAssetType.Texture2DArray] = LoadIcon(\"d_Texture Icon\"),\n                [SubAssetType.Cubemap] = LoadIcon(\"d_Cubemap Icon\", \"PreTexCube\"),\n                [SubAssetType.SpineAnimation] = LoadIcon(\"d_Animation Icon\"),\n                [SubAssetType.SpineSkeletonData] = LoadIcon(\"d_Animation Icon\"),\n                [SubAssetType.PhysicsMaterial2D] = LoadIcon(\"d_PhysicMaterial Icon\", \"d_Texture Icon\")\n            };\n        }\n        \n        /// <summary>\n        /// Loads a Unity Editor icon with optional fallback support.\n        /// </summary>\n        private static Texture2D LoadIcon(string iconName, string fallbackIcon = null)\n        {\n            Texture2D icon = EditorGUIUtility.IconContent(iconName).image as Texture2D;\n            if (icon == null && !string.IsNullOrEmpty(fallbackIcon))\n            {\n                icon = EditorGUIUtility.IconContent(fallbackIcon).image as Texture2D;\n            }\n            return icon ?? EditorGUIUtility.IconContent(\"DefaultAsset Icon\").image as Texture2D;\n        }\n        \n        \n        private readonly List<SubAssetDetail> details = new List<SubAssetDetail>();\n        \n        public AssetRefUI(string guid, string path, List<long> localIds):base(guid, path)\n        {\n            var file = AssetFinderCacheAsset.GetFile(guid);\n\n            for (var i = 0; i < localIds.Count; i++)\n            {\n                long localId = localIds[i];\n                var detail = file.GetSubDetail(localId);\n                details.Add(detail);\n            }\n        }\n        \n        public void DrawSubDetails(Rect rect, SubAssetDetail detail)\n        {\n            if (detail == null) return;\n            rect.xMin += 16f;\n            rect.height = AssetFinderTheme.Current.TreeItemHeight;\n            \n            Rect iconRect = new Rect(rect.x, rect.y, 16f, 16f);\n            var icon = GetIcon(detail.type);\n\n            if (icon != null)\n            {\n                GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit);\n            }\n            \n            // Draw label underneath\n            var labelRect = new Rect(rect.x + 16f, rect.y, rect.width, 16);\n            GUI.Label(labelRect, detail.name);\n        }\n        \n        public void Draw(ref Rect rect)\n        {\n            // Draw main Asset\n            Rect r1 = rect;\n            DrawAsset(ref r1, true, false);\n            rect.y += 18f;\n            \n            // Draw references: should exclude main asset?\n            for (var i = 0; i < details.Count; i++)\n            {\n                var detail = details[i];\n                if (detail == null) continue;\n                \n                DrawSubDetails(rect, details[i]);\n                rect.y += 18f;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/AssetRefUI.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a0104b91001f4474b7ccdb647abfeef2\ntimeCreated: 1738922219"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/AssetUI.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public abstract partial class AssetUI\n    {\n        internal static readonly FolderUI NO_PARENT = new FolderUI(string.Empty, string.Empty);\n        \n        // Cache\n        internal static readonly Dictionary<string, AssetUI> cache = new Dictionary<string, AssetUI>();\n        internal static AssetUI Get(string guid, bool autoNew = false)\n        {\n            AssetUI result = cache.GetValueOrDefault(guid);\n            if (!autoNew || result != null) return result;\n\n            string path = AssetDatabase.GUIDToAssetPath(guid);\n            if (string.IsNullOrEmpty(path)) return null;\n            \n            bool isFolder = AssetDatabase.IsValidFolder(path);\n            result = isFolder ? (AssetUI)new FolderUI(guid, path) : (AssetUI)new FileUI(guid, path);\n            cache[guid] = result;\n            return result;\n        }\n\n        internal static T Get<T>(string guid, bool autoNew = false) where T: AssetUI\n        {\n            return Get(guid, autoNew) as T;\n        }\n        \n        \n        // Instance variables\n        public string path;\n        public readonly string guid;\n        [NonSerialized] internal AssetUI _parent;\n        \n        public void RefreshPath()\n        {\n            path = AssetDatabase.GUIDToAssetPath(guid);\n            _parent = null;\n            \n            // also clear cached content\n            nameContent?.Clear();\n            pathContent?.Clear();\n        }\n        \n        public AssetUI Parent\n        {\n            get\n            {\n                if (_parent != null) return _parent;\n                int idx = path.LastIndexOf(\"/\", StringComparison.Ordinal);\n                if (idx == -1) return _parent = NO_PARENT;\n                \n                string pPath = path.Substring(0, idx);\n                string pGUID = AssetDatabase.AssetPathToGUID(pPath);\n                _parent = Get(pGUID, true) ?? NO_PARENT;\n                return _parent;\n            }\n        }\n        \n        protected AssetUI(string guid, string path)\n        {\n            this.guid = guid;\n            this.path = path;\n        }\n    }\n\n    internal class AssetNameContent\n    {\n        internal GUIContent nameContent;\n        internal GUIContent extContent;\n        internal float nameWidth;\n        internal float extWidth;\n        internal bool isValid => nameContent != null;\n        internal bool hasExt => extContent != null;\n        \n        internal void Clear()\n        {\n            nameContent = null;\n            extContent = null;\n            nameWidth = 0;\n            extWidth = 0;\n        }\n        \n        internal void Refresh(string path)\n        {\n            string assetName = Path.GetFileNameWithoutExtension(path);\n            string ext = Path.GetExtension(path);\n            \n            // do not use tooltip (as many files with the same name may shared this content)\n            nameContent = AssetFinderGUIContent.FromString(assetName); \n            nameWidth = EditorStyles.label.CalcSize(nameContent).x;\n            extContent = string.IsNullOrEmpty(ext) ? null : AssetFinderGUIContent.FromString(ext);\n            extWidth = string.IsNullOrEmpty(ext) ? 0 : EditorStyles.label.CalcSize(extContent).x;\n        }\n    }\n    \n    internal class AssetPathContent\n    {\n        internal GUIContent pathContent;\n        internal float pathWidth;\n        internal bool isValid => pathContent != null;\n        internal void Clear()\n        {\n            pathContent = null;\n            pathWidth = 0;\n        }\n        \n        internal void Refresh(string path)\n        {            \n            // do not use tooltip (as many files with the same name may shared this content)\n            pathContent = AssetFinderGUIContent.FromString(path); \n            pathWidth = EditorStyles.label.CalcSize(pathContent).x;\n        }\n    }\n    \n    \n\n    partial class AssetUI // GUID Content\n    {\n        // CONST\n        public const float GUID_WIDTH = 250f;\n        internal GUIContent guidContent;\n        \n        public bool DrawGuid(ref Rect rect)\n        {\n            if (guidContent == null) guidContent = new GUIContent(guid, \"Click to copy GUID\");\n            Rect guidRect = GUI2.LeftRect(GUID_WIDTH, ref rect);\n            if (!GUI.Button(guidRect, guidContent)) return false;\n            \n            // Clicked\n            EditorGUIUtility.systemCopyBuffer = guid;\n            AssetFinderLOG.Log(\"Copied AssetFinderID Value: \" + EditorGUIUtility.systemCopyBuffer);\n            return true;\n        }\n    }\n\n    partial class AssetUI\n    {\n        [NonSerialized] internal AssetNameContent nameContent;\n        [NonSerialized] internal AssetPathContent pathContent;\n        \n        public void DrawAssetPath(ref Rect rect)\n        {\n            if (this == NO_PARENT) return;\n            if (pathContent == null) pathContent = new AssetPathContent();\n            if (!pathContent.isValid) pathContent.Refresh(path);\n            \n            using (AssetFinderGUI.Color(GUI.color.Alpha(0.5f)))\n            {\n                Rect pathRect = GUI2.LeftRect(pathContent.pathWidth, ref rect); \n                GUI.Label(pathRect, pathContent.pathContent, EditorStyles.label);    \n            }\n        }\n        \n        public void DrawAsset(ref Rect rect, bool withExt, bool withPath)\n        {\n            if (withPath)\n            {\n                AssetUI p = Parent;\n                if (p != NO_PARENT) p.DrawAssetPath(ref rect);\n            }\n            \n            // Draw AssetIcon\n            Rect iconRect = GUI2.LeftRect(16f, ref rect);\n            if (Event.current.type == EventType.Repaint)\n            {\n                Texture icon = AssetDatabase.GetCachedIcon(path);\n                if (icon != null) GUI.DrawTexture(iconRect, icon, ScaleMode.ScaleToFit);\n            }\n            \n            // Draw AssetName\n            if (nameContent == null) nameContent = new AssetNameContent();\n            if (!nameContent.isValid) nameContent.Refresh(path);\n            \n            Rect nameRect = GUI2.LeftRect(nameContent.nameWidth, ref rect);\n            GUI.Label(nameRect, nameContent.nameContent, EditorStyles.label);\n\n            // Draw extension\n            if (!withExt || !nameContent.hasExt) return;\n            using (AssetFinderGUI.Color(GUI.color.Alpha(0.5f)))\n            {\n                Rect extRect = GUI2.LeftRect(nameContent.extWidth, ref rect);\n                GUI.Label(extRect, nameContent.extContent, EditorStyles.label);     \n            }\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/AssetUI.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e5625265bccf4ca78a1745e92a5903b0\ntimeCreated: 1737956390"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/FileUI.cs",
    "content": "namespace VirtueSky.AssetFinder.Editor\n{\n    internal class FileUI : AssetUI\n    {\n        internal FileUI(string guid, string path) : base(guid, path){}\n        // Draw all subAssets???\n        \n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/FileUI.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4d14b3d72c054a9fbbd8ee474864fb39\ntimeCreated: 1737957263"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/FolderUI.cs",
    "content": "\nnamespace VirtueSky.AssetFinder.Editor\n{\n    internal class FolderUI : AssetUI\n    {\n        internal FolderUI(string guid, string path) : base(guid, path){}\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI/FolderUI.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b48108ae49c7431f8485fd4b3dd5371d\ntimeCreated: 1737955553"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/UI.meta",
    "content": "fileFormatVersion: 2\nguid: 27ba266e29bc4c20bb9dbf1ec684ea9b\ntimeCreated: 1737955455"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderInitializer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public static class AssetFinderInitializer\n    {\n        [InitializeOnLoadMethod]\n        static void Init()\n        {\n            EditorApplication.update -= DelayInit;\n            EditorApplication.update += DelayInit;\n            \n            AssemblyReloadEvents.afterAssemblyReload  -= Reload;\n            AssemblyReloadEvents.afterAssemblyReload  += Reload;\n            \n            EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;\n            EditorApplication.playModeStateChanged += OnPlayModeStateChanged; \n        }\n\n        private static void OnPlayModeStateChanged(PlayModeStateChange state)\n        {\n            switch (state)\n            {\n                case PlayModeStateChange.EnteredPlayMode:\n                    break;\n                case PlayModeStateChange.EnteredEditMode:  \n                {\n                    Reload();\n                    if (AssetFinderCache.Api != null && !AssetFinderSettingExt.disable)\n                    {\n                        AssetFinderCache.Api.IncrementalRefresh();\n                    }\n                    break;\n                }\n            }\n        }\n        \n        static void Reload()\n        {\n            AssetFinderAddressable.Scan();\n            AssetFinderCache.Reload();\n            \n            // Re-init all windows\n            var allWindows = Resources.FindObjectsOfTypeAll<AssetFinderWindowAll>();\n            for (var i = 0; i < allWindows.Length; i++)\n            {\n                allWindows[i].Reload(); \n            }\n        }\n        \n        \n        static void DelayInit()\n        {\n            if (EditorApplication.isCompiling || EditorApplication.isUpdating)\n            {\n                AssetFinderLOG.Log(\"Keep waiting...\");\n                return;\n            }\n            \n            EditorApplication.update -= DelayInit;\n            \n            // Simple type search scoped to Assets/ only\n            string[] cache = AssetDatabase.FindAssets(\"t:AssetFinderCacheAsset\", new[] { \"Assets\" });\n            if (cache.Length == 0) \n            {\n                return; // No cache found\n            }\n            \n            // Try to load the first valid cache asset\n            for (int i = 0; i < cache.Length; i++)\n            {\n                string assetPath = AssetDatabase.GUIDToAssetPath(cache[i]);\n                if (string.IsNullOrEmpty(assetPath)) continue;\n                \n                var cache0 = AssetDatabase.LoadAssetAtPath<AssetFinderCacheAsset>(assetPath);\n                if (cache0 != null)\n                {\n                    AssetFinderCacheAsset.Init(cache0);\n                    return;\n                }\n            }\n            \n            AssetFinderLOG.LogWarning(\"FR2: Cache assets found but all failed to load!\");\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderInitializer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b745caddec1cd2542b746816dd28ed55\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderLightmap.cs",
    "content": "// deleted"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderLightmap.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4cba24c6726bc5648b3b290eb439584d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderTerrain.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n\n    internal static class AssetFinderTerrain\n    {\n\t    [Serializable] internal class TerrainTextureData\n\t    {\n\t\t    public Texture2D[] textures;\n\t\t    public TerrainTextureData(params Texture2D[] param)\n\t\t    {\n\t\t\t    var count = 0;\n\t\t\t    if (param != null) count = param.Length;\n\n\t\t\t    textures = new Texture2D[count];\n\t\t\t    for (var i = 0; i < count; i++)\n\t\t\t    {\n\t\t\t\t    textures[i] = param[i];\n\t\t\t    }\n\t\t    }\n\t    }\n\t    \n\t    internal static int ReplaceTerrainTextureDatas(TerrainData terrain, Texture2D fromObj, Texture2D toObj)\n\t    {\n\t\t    var found = 0;\n#if UNITY_2018_3_OR_NEWER\n\t\t    TerrainLayer[] arr3 = terrain.terrainLayers;\n\t\t    for (var i = 0; i < arr3.Length; i++)\n\t\t    {\n\t\t\t    if (arr3[i].normalMapTexture == fromObj)\n\t\t\t    {\n\t\t\t\t    found++;\n\t\t\t\t    arr3[i].normalMapTexture = toObj;\n\t\t\t    }\n\n\t\t\t    if (arr3[i].maskMapTexture == fromObj)\n\t\t\t    {\n\t\t\t\t    found++;\n\t\t\t\t    arr3[i].maskMapTexture = toObj;\n\t\t\t    }\n\n\t\t\t    if (arr3[i].diffuseTexture == fromObj)\n\t\t\t    {\n\t\t\t\t    found++;\n\t\t\t\t    arr3[i].diffuseTexture = toObj;\n\t\t\t    }\n\t\t    }\n\n\t\t    terrain.terrainLayers = arr3;\n#else\n                    var arr3 = terrain.splatPrototypes;\n                    for (var i = 0; i < arr3.Length; i++)\n                    {\n                        if (arr3[i].texture ==  fromObj)\n                        {\n                            found++;\n                            arr3[i].texture = toObj;\n                        }\n\n                        if (arr3[i].normalMap ==  fromObj)\n                        {\n                            found++;\n                            arr3[i].normalMap = toObj;\n                        }\n                    }\n\n                    terrain.splatPrototypes = arr3;\n#endif\n\t\t    return found;\n\t    }\n\t    \n        internal static TerrainTextureData[] GetTerrainTextureDatas(TerrainData data)\n        {\n#if UNITY_2018_3_OR_NEWER\n            if (data == null || data.terrainLayers == null)\n            {\n                return new TerrainTextureData[] { };\n            }\n            \n            var arr = new TerrainTextureData[data.terrainLayers.Length];\n            for (var i = 0; i < data.terrainLayers.Length; i++)\n            {\n                TerrainLayer layer = data.terrainLayers[i];\n                arr[i] = layer == null ? new TerrainTextureData()\n                    : new TerrainTextureData(\n                        layer.normalMapTexture,\n                        layer.maskMapTexture,\n                        layer.diffuseTexture\n                    );\n            }\n\n            return arr;\n#else\n\t\t\tvar arr = new TerrainTextureData[data.splatPrototypes.Length];\n\t\t\tfor(int i = 0; i < data.splatPrototypes.Length; i++)\n\t\t\t{\n\t\t\t\tvar layer = data.splatPrototypes[i];\n\t\t\t\tarr[i] = new TerrainTextureData\n\t\t\t\t(\n\t\t\t\t\tlayer.normalMap,\n\t\t\t\t\tlayer.texture\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn arr;\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderTerrain.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 63dd5db1ae5552847acf741487c1af2e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderUSelection.cs",
    "content": "using System.Text;\nusing UnityEditor;\nusing UnityEngine;\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public static class AssetFinderUSelection\n    {\n        private static readonly StringBuilder sb = new StringBuilder();\n\n        internal static void StartDebugReference()\n        {\n            Selection.selectionChanged -= DebugAssetReference;\n            Selection.selectionChanged += DebugAssetReference;\n        }\n\n        internal static void StopDebugReference()\n        {\n            Selection.selectionChanged -= DebugAssetReference;\n        }\n\n        private static void DebugAssetReference()\n        {\n            if (!AssetFinderCacheAsset.isReady) return;\n            \n            Object activeObject = Selection.activeObject;\n            if (activeObject == null) return;\n            \n            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(activeObject, out string guid, out long fileId);\n            var isMainAsset = AssetDatabase.IsMainAsset(activeObject);\n            var usageList = AssetFinderCacheAsset.CollectUsage(guid);\n            var usedByList = AssetFinderCacheAsset.CollectUsedBy(guid, isMainAsset ? -1 : fileId);\n            \n            sb.Clear();\n            sb.AppendLine($\"{guid}:{fileId} : {AssetDatabase.GUIDToAssetPath(guid)}\");\n            \n            sb.AppendLine($\"Used: {usageList.Count}\\n\");\n            for (var i = 0; i < usageList.Count; i++)\n            {\n                AssetFinderIDRef usage = usageList[i];\n                var (useGUID, useFileId) = AssetFinderCacheAsset.GetGuidAndFileId(usage.toId);\n                sb.AppendLine($\"{useGUID}:{useFileId} - {usage} \\t\\t {AssetDatabase.GUIDToAssetPath(useGUID)}\");\n            }\n\n            sb.AppendLine($\"UsedBy: {usedByList.Count}\\n\");\n            for (var i = 0; i < usedByList.Count; i++)\n            {\n                AssetFinderIDRef useBy = usedByList[i];\n                var (useByGUID, _) = AssetFinderCacheAsset.GetGuidAndFileId(useBy.fromId);\n                sb.AppendLine($\"{useByGUID} - {useBy} \\t\\t {AssetDatabase.GUIDToAssetPath(useByGUID)}\");\n            }\n            \n            Debug.Log(sb.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity/AssetFinderUSelection.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 25969e281a1de8b48b8c1191090539a3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Unity.meta",
    "content": "fileFormatVersion: 2\nguid: 1704823120c14e9ebb9eb9d5ae580068\ntimeCreated: 1730993756"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Utils/AssetFinderTimeSlice.cs",
    "content": "#define AssetFinderDEBUG\n\nusing System;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.AssetFinder.Editor\n{\n    public class AssetFinderTimeSlice\n    {\n        private readonly Action onCompleteCallback;\n        private readonly Action<int> processingAction;\n        private readonly Func<int> targetCountFunc;\n\n        private int currentIndex;\n        public readonly float timeSlice = 1 / 100f;\n\n        public AssetFinderTimeSlice(Func<int> countFunc, Action<int> action, Action onComplete = null)\n        {\n            targetCountFunc = countFunc;\n            processingAction = action;\n            onCompleteCallback = onComplete;\n        }\n\n        public void Start()\n        {\n            currentIndex = 0;\n            EditorApplication.update += ProcessQueue;\n        }\n\n        public void Stop()\n        {\n            EditorApplication.update -= ProcessQueue;\n        }\n\n        private void ProcessQueue()\n        {\n            float startTime = Time.realtimeSinceStartup;\n            int targetCount = targetCountFunc.Invoke();\n\n            // Process items within the time slice\n            while (currentIndex < targetCount)\n            {\n                processingAction.Invoke(currentIndex);\n                currentIndex++;\n\n                if (Time.realtimeSinceStartup - startTime >= timeSlice)\n                {\n                    #if AssetFinderDEBUG\n                    float pct = currentIndex * 100f / targetCount;\n                    AssetFinderLOG.Log($\"Progress: {pct:0.00}% -  {currentIndex}/{targetCount}\");\n                    #endif\n                    return;\n                }\n            }\n\n            targetCount = targetCountFunc.Invoke();\n\n            // Stop processing if we've reached the target count\n            if (currentIndex < targetCount) return;\n\n            EditorApplication.update -= ProcessQueue;\n            onCompleteCallback?.Invoke();\n        }\n    }\n}\n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Utils/AssetFinderTimeSlice.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 93892da2f0d8ba448909a3fed223cc0a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2/Utils.meta",
    "content": "fileFormatVersion: 2\nguid: fc17651b6a294c0897caad1ae823f6d1\ntimeCreated: 1730992938"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor/v2.meta",
    "content": "fileFormatVersion: 2\nguid: 8e5457f2d0edd449e939840c60b51a84\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 60f91a6c3e6d33542af8e8d8aca5178e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/AssetFinder.meta",
    "content": "fileFormatVersion: 2\nguid: ad1cc3dbf7ddd174b8e4d79693c7e3c3\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Editor/AudioWindowEditor.cs",
    "content": "﻿#if UNITY_EDITOR\nusing UnityEditor;\nusing VirtueSky.Audio;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.AudioEditor\n{\n    public class AudioWindowEditor : EditorWindow\n    {\n        public static void CreateSoundData()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<SoundData>(\"/Audio/SoundData\", \"sound_data\");\n        }\n\n\n        #region Event Music\n\n        public static void CreatePlayMusicEvent()\n        {\n            CreateAsset.CreateScriptableAssets<PlayMusicEvent>(\"/Audio/Music_Event\", \"play_music_event\");\n        }\n\n        public static void CreatePauseMusicEvent()\n        {\n            CreateAsset.CreateScriptableAssets<PauseMusicEvent>(\"/Audio/Music_Event\", \"pause_music_event\");\n        }\n\n        public static void CreateResumeMusicEvent()\n        {\n            CreateAsset.CreateScriptableAssets<ResumeMusicEvent>(\"/Audio/Music_Event\",\n                \"resume_music_event\");\n        }\n\n        public static void CreateStopMusicEvent()\n        {\n            CreateAsset.CreateScriptableAssets<StopMusicEvent>(\"/Audio/Music_Event\", \"stop_music_event\");\n        }\n\n        #endregion\n\n        #region Event Sfx\n\n        public static void CreatePlaySfxEvent()\n        {\n            CreateAsset.CreateScriptableAssets<PlaySfxEvent>(\"/Audio/Sfx_Event\", \"play_sfx_event\");\n        }\n\n        public static void CreatePauseSfxEvent()\n        {\n            CreateAsset.CreateScriptableAssets<PauseSfxEvent>(\"/Audio/Sfx_Event\", \"pause_sfx_event\");\n        }\n\n        public static void CreateFinishSfxEvent()\n        {\n            CreateAsset.CreateScriptableAssets<FinishSfxEvent>(\"/Audio/Sfx_Event\", \"finish_sfx_event\");\n        }\n\n        public static void CreateResumeSfxEvent()\n        {\n            CreateAsset.CreateScriptableAssets<ResumeSfxEvent>(\"/Audio/Sfx_Event\", \"resume_sfx_event\");\n        }\n\n        public static void CreateStopSfxEvent()\n        {\n            CreateAsset.CreateScriptableAssets<StopSfxEvent>(\"/Audio/Sfx_Event\", \"stop_sfx_event\");\n        }\n\n        public static void CreateStopAllSfxEvent()\n        {\n            CreateAsset.CreateScriptableAssets<StopAllSfxEvent>(\"/Audio/Sfx_Event\", \"stop_all_sfx_event\");\n        }\n\n        #endregion\n\n        #region Volume Change\n\n        public static void CreateMusicVolume()\n        {\n            CreateAsset.CreateScriptableAssets<MusicVolumeChange>(\"/Audio/Volume_Change\", \"music_volume\");\n        }\n\n        public static void CreateSfxVolume()\n        {\n            CreateAsset.CreateScriptableAssets<SfxVolumeChange>(\"/Audio/Volume_Change\", \"sfx_volume\");\n        }\n\n        #endregion\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Audio/Editor/AudioWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5dbf320248604081a9cb6de994848425\ntimeCreated: 1697699209"
  },
  {
    "path": "VirtueSky/Audio/Editor/EditorAudioPreview.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing System;\nusing System.Reflection;\n\nnamespace VirtueSky.AudioEditor\n{\n    internal static class EditorAudioPreview\n    {\n        static readonly Type AudioUtilType;\n        static readonly MethodInfo PlayMethod;\n        static readonly MethodInfo StopAllMethod;\n        static readonly MethodInfo StopOneMethod;\n\n        // Hỗ trợ nhiều biến thể kiểm tra trạng thái phát\n        static readonly MethodInfo IsPlayingClipMethod; // IsPreviewClipPlaying(AudioClip)\n        static readonly MethodInfo IsPlayingNoArgMethod; // IsPreviewClipPlaying()\n        static readonly MethodInfo GetPreviewClipMethod; // GetPreviewClip()\n\n        static EditorAudioPreview()\n        {\n            AudioUtilType = typeof(AudioImporter).Assembly.GetType(\"UnityEditor.AudioUtil\");\n            var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;\n\n            // PlayPreviewClip(clip, startSample, loop[, honorPlayOneShot?])\n            PlayMethod = AudioUtilType.GetMethod(\"PlayPreviewClip\", flags, null,\n                             new Type[] { typeof(AudioClip), typeof(int), typeof(bool) }, null)\n                         ?? AudioUtilType.GetMethod(\"PlayPreviewClip\", flags, null,\n                             new Type[] { typeof(AudioClip), typeof(int), typeof(bool), typeof(bool) }, null);\n\n            StopAllMethod = AudioUtilType.GetMethod(\"StopAllPreviewClips\", flags);\n            StopOneMethod = AudioUtilType.GetMethod(\"StopPreviewClip\", flags, null,\n                new Type[] { typeof(AudioClip) }, null);\n\n            IsPlayingClipMethod = AudioUtilType.GetMethod(\"IsPreviewClipPlaying\", flags, null,\n                new Type[] { typeof(AudioClip) }, null);\n            IsPlayingNoArgMethod = AudioUtilType.GetMethod(\"IsPreviewClipPlaying\", flags, null,\n                Type.EmptyTypes, null);\n            GetPreviewClipMethod = AudioUtilType.GetMethod(\"GetPreviewClip\", flags);\n        }\n\n        public static void Play(AudioClip clip, bool loop = false, int startSample = 0)\n        {\n            if (!clip || PlayMethod == null) return;\n            var args = PlayMethod.GetParameters().Length == 3\n                ? new object[] { clip, startSample, loop }\n                : new object[] { clip, startSample, loop, false };\n            PlayMethod.Invoke(null, args);\n        }\n\n        public static void Stop(AudioClip clip = null)\n        {\n            if (clip != null && StopOneMethod != null) StopOneMethod.Invoke(null, new object[] { clip });\n            else if (StopAllMethod != null) StopAllMethod.Invoke(null, null);\n        }\n\n        public static bool IsPlaying(AudioClip clip = null)\n        {\n            try\n            {\n                if (IsPlayingClipMethod != null)\n                    return (bool)IsPlayingClipMethod.Invoke(null, new object[] { clip });\n\n                if (IsPlayingNoArgMethod != null)\n                    return (bool)IsPlayingNoArgMethod.Invoke(null, null);\n\n                if (GetPreviewClipMethod != null)\n                {\n                    var cur = GetPreviewClipMethod.Invoke(null, null) as AudioClip;\n                    return clip ? cur == clip : cur != null;\n                }\n            }\n            catch\n            {\n                /* ignore reflection issues */\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Editor/EditorAudioPreview.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1b9f795e3e2e4b72a0f5911284392590\ntimeCreated: 1757940109"
  },
  {
    "path": "VirtueSky/Audio/Editor/SoundDataEditor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Audio;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.AudioEditor\n{\n    [CustomEditor(typeof(SoundData))]\n    public class SoundDataEditor : Editor\n    {\n        SerializedProperty clipsProp;\n\n        // State preview\n        int selectedIndex = 0;\n        float playheadSec = 0f;\n        float loopA = -1f, loopB = -1f;\n        bool selectingLoop = false;\n\n        AudioClip activeClip;\n        AudioClip lastPlayed;\n        double lastTickTime;\n        bool isPlaying = false;\n        int lastKnownSamplePosition = 0;\n\n        Action externalRepaintCallback;\n\n        public void SetExternalRepaintCallback(Action callback)\n        {\n            externalRepaintCallback = callback;\n        }\n\n        const float TimebarH = 22f;\n        const float LaneH = 38f;\n\n        void OnEnable()\n        {\n            clipsProp = serializedObject.FindProperty(\"audioClips\");\n            EditorApplication.update += OnEditorUpdate;\n        }\n\n        void OnDisable()\n        {\n            EditorApplication.update -= OnEditorUpdate;\n\n            isPlaying = false;\n            EditorAudioPreview.Stop();\n            lastPlayed = null;\n            activeClip = null;\n            externalRepaintCallback = null;\n        }\n\n        void RequestRepaint()\n        {\n            base.Repaint();\n            externalRepaintCallback?.Invoke();\n        }\n\n        GUIStyle StyleLabel()\n        {\n            var style = new GUIStyle();\n            style.fontSize = 14;\n            style.normal.textColor = Color.white;\n            return style;\n        }\n\n        public override void OnInspectorGUI()\n        {\n            DrawDefaultInspector();\n\n            EditorGUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"preview_sound_data\", \"Editor Preview\", DrawPreview, true);\n            serializedObject.Update();\n            serializedObject.ApplyModifiedProperties();\n        }\n\n        void DrawPreview()\n        {\n            int total = clipsProp != null ? clipsProp.arraySize : 0;\n            if (total <= 0)\n            {\n                EditorGUILayout.HelpBox(\"Add AudioClip to preview.\", MessageType.Info);\n                return;\n            }\n\n            List<int> indexMap = new List<int>(total);\n            List<string> options = new List<string>(total);\n\n            for (int i = 0; i < total; i++)\n            {\n                var el = clipsProp.GetArrayElementAtIndex(i);\n                var clip = el.objectReferenceValue as AudioClip;\n                if (clip != null)\n                {\n                    indexMap.Add(i);\n                    options.Add($\"{i} - {clip.name}\");\n                }\n            }\n\n            if (indexMap.Count == 0)\n            {\n                EditorGUILayout.HelpBox(\n                    \"The AudioClips list has elements but they are all null. Drag and drop AudioClips into it or delete the null elements.\",\n                    MessageType.Info\n                );\n\n                if (isPlaying)\n                {\n                    isPlaying = false;\n                    EditorAudioPreview.Stop();\n                    lastPlayed = null;\n                    activeClip = null;\n                }\n\n                return;\n            }\n\n            selectedIndex = Mathf.Clamp(selectedIndex, 0, indexMap.Count - 1);\n\n            int newSel = EditorGUILayout.Popup(\"Preview Clip\", selectedIndex, options.ToArray());\n\n            int propIndex = indexMap[newSel];\n            var selEl = clipsProp.GetArrayElementAtIndex(propIndex);\n            var sel = selEl.objectReferenceValue as AudioClip;\n\n            if (newSel != selectedIndex || sel != activeClip)\n            {\n                isPlaying = false;\n                EditorAudioPreview.Stop(activeClip);\n                selectedIndex = newSel;\n                activeClip = sel;\n                playheadSec = 0f;\n                lastPlayed = null;\n            }\n\n            using (new EditorGUI.DisabledScope(activeClip == null))\n            {\n                DrawTimeline(activeClip);\n                DrawTransport(activeClip);\n            }\n        }\n\n        /// <summary>\n        /// Update per frame when editor is active\n        /// </summary>\n        void OnEditorUpdate()\n        {\n            if (!activeClip || !isPlaying) return;\n\n            // Sync playhead with actual audio playback position\n            float actualPosition = GetAudioPreviewPosition(activeClip);\n            \n            if (actualPosition >= 0f)\n            {\n                playheadSec = actualPosition;\n            }\n            else\n            {\n                // Fallback to time-based calculation if position can't be retrieved\n                double now = EditorApplication.timeSinceStartup;\n                double dt = System.Math.Max(0, now - lastTickTime);\n                lastTickTime = now;\n                playheadSec += (float)dt;\n            }\n\n            if (HasLoop())\n            {\n                float a = Mathf.Min(loopA, loopB);\n                float b = Mathf.Max(loopA, loopB);\n                if (playheadSec > b)\n                {\n                    playheadSec = a;\n                    if (isPlaying)\n                    {\n                        int startSample = Mathf.Clamp(Mathf.RoundToInt(a * activeClip.frequency), 0,\n                            activeClip.samples - 1);\n                        EditorAudioPreview.Play(activeClip, false, startSample);\n                        lastTickTime = EditorApplication.timeSinceStartup;\n                    }\n                }\n            }\n            else if (playheadSec > activeClip.length)\n            {\n                // Auto-return to 0 and stop\n                isPlaying = false;\n                EditorAudioPreview.Stop(activeClip);\n                lastPlayed = null;\n                playheadSec = 0f;\n            }\n\n            // Always repaint when playing to ensure smooth animation\n            RequestRepaint();\n        }\n        \n        /// <summary>\n        /// Get current audio preview position using reflection\n        /// </summary>\n        float GetAudioPreviewPosition(AudioClip clip)\n        {\n            if (clip == null) return -1f;\n            \n            try\n            {\n                var unityEditorAssembly = typeof(AudioImporter).Assembly;\n                var audioUtilClass = unityEditorAssembly.GetType(\"UnityEditor.AudioUtil\");\n                \n                // Try to get the playing sample position\n                var method = audioUtilClass.GetMethod(\"GetClipSamplePosition\",\n                    System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);\n                \n                if (method != null)\n                {\n                    var result = method.Invoke(null, new object[] { clip });\n                    if (result != null)\n                    {\n                        int samplePosition = (int)result;\n                        if (samplePosition >= 0 && clip.frequency > 0)\n                        {\n                            return (float)samplePosition / clip.frequency;\n                        }\n                    }\n                }\n            }\n            catch\n            {\n                // Fallback to time-based calculation\n            }\n            \n            return -1f;\n        }\n\n        // ====== Timeline UI ======\n        void DrawTimeline(AudioClip clip)\n        {\n            // Timebar (ticks)\n            var timeRect = GUILayoutUtility.GetRect(0, 1000, TimebarH, TimebarH);\n            EditorGUI.DrawRect(timeRect, new Color(0.11f, 0.11f, 0.11f));\n            DrawTicks(timeRect, clip.length);\n\n            // Lane (playhead + loop Aâ€“B)\n            var laneRect = GUILayoutUtility.GetRect(0, 1000, LaneH, LaneH);\n            EditorGUI.DrawRect(laneRect, new Color(0.09f, 0.09f, 0.09f));\n\n            if (HasLoop())\n            {\n                float a = Mathf.Clamp(Mathf.Min(loopA, loopB), 0, clip.length);\n                float b = Mathf.Clamp(Mathf.Max(loopA, loopB), 0, clip.length);\n                var r = TimeRangeToRect(laneRect, 0, clip.length, a, b);\n                EditorGUI.DrawRect(r, new Color(0.2f, 0.6f, 0.3f, 0.20f));\n                DrawBorder(r, new Color(0.3f, 0.9f, 0.5f, 0.85f));\n            }\n\n            // Playhead\n            float px = TimeToPixel(laneRect, 0, clip.length, playheadSec);\n            EditorGUI.DrawRect(new Rect(px, laneRect.y, 2f, laneRect.height), new Color(1f, 0.85f, 0.2f));\n\n            HandleLaneInput(laneRect, clip.length);\n        }\n\n        void DrawTransport(AudioClip clip)\n        {\n            using (new EditorGUILayout.HorizontalScope())\n            {\n                string playLabel = isPlaying ? \"Restart\" : \"Play from Head\";\n                if (GUILayout.Button(playLabel, GUILayout.Height(22)))\n                {\n                    if (clip)\n                    {\n                        if (isPlaying)\n                        {\n                            EditorAudioPreview.Stop(clip);\n                            playheadSec = 0f;\n                            lastKnownSamplePosition = 0;\n                        }\n\n                        if (lastPlayed && lastPlayed != clip) EditorAudioPreview.Stop(lastPlayed);\n\n                        lastPlayed = clip;\n                        isPlaying = true;\n\n                        int startSample = Mathf.Clamp(Mathf.RoundToInt(playheadSec * clip.frequency), 0,\n                            clip.samples - 1);\n                        lastKnownSamplePosition = startSample;\n                        EditorAudioPreview.Play(clip, false, startSample);\n                        lastTickTime = EditorApplication.timeSinceStartup;\n                    }\n                }\n\n                if (GUILayout.Button(\"Stop\", GUILayout.Height(22)))\n                {\n                    if (clip)\n                    {\n                        isPlaying = false;\n                        EditorAudioPreview.Stop();\n                        lastPlayed = null;\n                        playheadSec = 0f; // Reset playhead to beginning when stopped\n                        RequestRepaint();\n                    }\n                }\n\n                if (GUILayout.Button(\"To Start\", GUILayout.Height(22)))\n                {\n                    if (clip)\n                    {\n                        playheadSec = 0f;\n                        lastKnownSamplePosition = 0;\n                        if (isPlaying)\n                        {\n                            EditorAudioPreview.Play(clip, false, 0);\n                            lastTickTime = EditorApplication.timeSinceStartup;\n                        }\n                        else\n                        {\n                            RequestRepaint(); // Only repaint if not playing to update the UI\n                        }\n                    }\n                }\n\n                if (GUILayout.Button(\"â†º Set Loop A\", GUILayout.Height(22)))\n                {\n                    if (clip) loopA = Mathf.Clamp(playheadSec, 0, clip.length);\n                }\n\n                if (GUILayout.Button(\"â†» Set Loop B\", GUILayout.Height(22)))\n                {\n                    if (clip) loopB = Mathf.Clamp(playheadSec, 0, clip.length);\n                }\n\n                if (GUILayout.Button(\"Set Loop Full\", GUILayout.Height(22)))\n                {\n                    if (clip)\n                    {\n                        loopA = 0f;\n                        loopB = clip.length;\n                        if (isPlaying)\n                        {\n                            playheadSec = 0f;\n                            lastKnownSamplePosition = 0;\n                            EditorAudioPreview.Play(clip, false, 0);\n                            lastTickTime = EditorApplication.timeSinceStartup;\n                        }\n                        else\n                        {\n                            RequestRepaint(); // Only repaint if not playing to update the UI\n                        }\n                    }\n                }\n\n                if (GUILayout.Button(\"Clear Loop\", GUILayout.Height(22)))\n                {\n                    loopA = loopB = -1f;\n                    RequestRepaint(); // Repaint to update the UI immediately\n                }\n            }\n\n            EditorGUILayout.LabelField(\n                $\"Clip: {clip.name} â€¢ Length: {clip.length:0.000}s â€¢ Head: {playheadSec:0.000}s\" +\n                (HasLoop() ? $\" â€¢ Loop [{Mathf.Min(loopA, loopB):0.000} â€“ {Mathf.Max(loopA, loopB):0.000}]s\" : \"\")\n            );\n\n            EditorGUILayout.HelpBox(\n                \"Loop preview is controlled only by Set Loop A/B/Full or Clear Loop. When there is no Aâ€“B: playback will automatically return to 0s (auto-return).\",\n                MessageType.Info\n            );\n        }\n\n        // ====== Helpers ======\n        bool HasLoop() => loopA >= 0f && loopB >= 0f && !Mathf.Approximately(loopA, loopB);\n\n        void HandleLaneInput(Rect r, float len)\n        {\n            var e = Event.current;\n            if (!r.Contains(e.mousePosition) || len <= 0f) return;\n\n            if (e.type == EventType.MouseDown && e.button == 0)\n            {\n                playheadSec = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len);\n                // When user manually sets the playhead, update the audio preview\n                if (isPlaying && activeClip)\n                {\n                    int startSample = Mathf.Clamp(Mathf.RoundToInt(playheadSec * activeClip.frequency), 0,\n                        activeClip.samples - 1);\n                    lastKnownSamplePosition = startSample;\n                    EditorAudioPreview.Play(activeClip, false, startSample);\n                    lastTickTime = EditorApplication.timeSinceStartup;\n                }\n                e.Use();\n                RequestRepaint(); // Force repaint immediately to update the UI\n            }\n            else if (e.type == EventType.MouseDrag && e.button == 0)\n            {\n                playheadSec = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len);\n                // When dragging the playhead, update the audio preview to match the position\n                if (isPlaying && activeClip)\n                {\n                    int startSample = Mathf.Clamp(Mathf.RoundToInt(playheadSec * activeClip.frequency), 0,\n                        activeClip.samples - 1);\n                    lastKnownSamplePosition = startSample;\n                    EditorAudioPreview.Play(activeClip, false, startSample);\n                    lastTickTime = EditorApplication.timeSinceStartup;\n                }\n                e.Use();\n                RequestRepaint(); // Force repaint immediately to update the UI\n            }\n\n            if (e.type == EventType.MouseDown && e.button == 1)\n            {\n                loopA = loopB = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len);\n                selectingLoop = true;\n                e.Use();\n            }\n            else if (e.type == EventType.MouseDrag && e.button == 1 && selectingLoop)\n            {\n                loopB = Mathf.Clamp(PixelToTime(r, 0, len, e.mousePosition.x), 0, len);\n                e.Use();\n            }\n            else if (e.type == EventType.MouseUp && e.button == 1 && selectingLoop)\n            {\n                selectingLoop = false;\n                e.Use();\n            }\n        }\n\n        void DrawTicks(Rect r, float total)\n        {\n            if (total <= 0f) return;\n\n            float step = NiceStep(total);\n            Handles.BeginGUI();\n            Handles.color = new Color(0.6f, 0.6f, 0.6f, 0.7f);\n\n            for (float t = 0f; t <= total + 0.0001f; t += step)\n            {\n                float x = Mathf.Lerp(r.x, r.xMax, t / total);\n                Handles.DrawLine(new Vector2(x, r.y), new Vector2(x, r.yMax));\n            }\n\n            Handles.EndGUI();\n            \n            // Váº½ nhÃ£n sau Ä‘á»ƒ trÃ¡nh chá»“ng chÃ©o vá»›i cÃ¡c Ä‘Æ°á»ng káº»\n            for (float t = 0f; t <= total + 0.0001f; t += step)\n            {\n                float x = Mathf.Lerp(r.x, r.xMax, t / total);\n                var label = $\"{t:0.00}s\";\n                var size = GUI.skin.label.CalcSize(new GUIContent(label));\n                GUI.Label(new Rect(x + 2, r.y - 1, size.x, r.height), label);\n            }\n        }\n\n        float NiceStep(float total)\n        {\n            float[] steps = { 0.05f, 0.1f, 0.2f, 0.5f, 1f, 2f, 5f, 10f, 15f, 30f, 60f };\n            foreach (var s in steps)\n                if (total / s <= 12f)\n                    return s;\n            return 120f;\n        }\n\n        float TimeToPixel(Rect r, float start, float end, float t)\n        {\n            float u = Mathf.InverseLerp(start, end, t);\n            return Mathf.Lerp(r.x, r.xMax, u);\n        }\n\n        float PixelToTime(Rect r, float start, float end, float px)\n        {\n            float u = Mathf.InverseLerp(r.x, r.xMax, px);\n            return Mathf.Lerp(start, end, u);\n        }\n\n        Rect TimeRangeToRect(Rect r, float start, float end, float a, float b)\n        {\n            float ax = TimeToPixel(r, start, end, a);\n            float bx = TimeToPixel(r, start, end, b);\n            return Rect.MinMaxRect(Mathf.Min(ax, bx), r.y, Mathf.Max(ax, bx), r.yMax);\n        }\n\n        void DrawBorder(Rect r, Color c)\n        {\n            EditorGUI.DrawRect(new Rect(r.x, r.y, r.width, 2), c);\n            EditorGUI.DrawRect(new Rect(r.x, r.yMax - 2, r.width, 2), c);\n            EditorGUI.DrawRect(new Rect(r.x, r.y, 2, r.height), c);\n            EditorGUI.DrawRect(new Rect(r.xMax - 2, r.y, 2, r.height), c);\n        }\n    }\n}\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "VirtueSky/Audio/Editor/SoundDataEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 087c7c60e1b14a94ad7af200a4fbd940\ntimeCreated: 1757940241"
  },
  {
    "path": "VirtueSky/Audio/Editor/Virtuesky.Sunflower.Audio.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Audio.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:2ba9ab3e4292d6e4b81f0022dc854eee\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:ce8c6e3f188ed064f933ef35b46bf8bd\",\n        \"GUID:35d694408290717499b3838802212c7f\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Audio/Editor/Virtuesky.Sunflower.Audio.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: dcf049c718e6d4d0b8bbcaf56be706c2\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: c0b59c1b97996ee4f851fa88c2b8a3c6\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/AudioHelper.cs",
    "content": "namespace VirtueSky.Audio\n{\n    public static class AudioHelper\n    {\n        public static SoundCache PlaySfx(this SoundData soundData, PlaySfxEvent playSfxEvent) => playSfxEvent.Raise(soundData);\n        public static void PauseSfx(this SoundCache soundCache, PauseSfxEvent pauseSfxEvent) => pauseSfxEvent.Raise(soundCache);\n        public static void StopSfx(this SoundCache soundCache, StopSfxEvent stopSfxEvent) => stopSfxEvent.Raise(soundCache);\n        public static void ResumeSfx(this SoundCache soundCache, ResumeSfxEvent resumeSfxEvent) => resumeSfxEvent.Raise(soundCache);\n        public static void FinishSfx(this SoundCache soundCache, FinishSfxEvent finishSfxEvent) => finishSfxEvent.Raise(soundCache);\n        public static void StopAllSfx(this StopAllSfxEvent stopAllSfxEvent) => stopAllSfxEvent.Raise();\n\n        public static void PlayMusic(this SoundData soundData, PlayMusicEvent playMusicEvent) => playMusicEvent.Raise(soundData);\n        public static void StopMusic(this StopMusicEvent stopMusicEvent) => stopMusicEvent.Raise();\n        public static void PauseMusic(this PauseMusicEvent pauseMusicEvent) => pauseMusicEvent.Raise();\n        public static void ResumeMusic(this ResumeMusicEvent resumeMusicEvent) => resumeMusicEvent.Raise();\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/AudioHelper.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c28340e8673e4449905ac4eafb9b8bb1\ntimeCreated: 1727858865"
  },
  {
    "path": "VirtueSky/Audio/Runtime/AudioManager.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.DataType;\nusing VirtueSky.Inspector;\nusing VirtueSky.ObjectPooling;\nusing VirtueSky.Utils;\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\n\n\nnamespace VirtueSky.Audio\n{\n    [EditorIcon(\"icon_sound_mixer\"), HideMonoScript]\n    public class AudioManager : BaseMono\n    {\n        [Space] [SerializeField] private bool isDontDestroyOnLoad;\n        [SerializeField] private SoundComponent soundComponentPrefab;\n\n        [SerializeField] private Transform audioHolder;\n\n        [Space] [TitleColor(\"Music Listening\", CustomColor.Aqua, CustomColor.Lime)] [SerializeField]\n        private PlayMusicEvent eventPlayMusic;\n\n        [SerializeField] private StopMusicEvent eventStopMusic;\n        [SerializeField] private PauseMusicEvent eventPauseMusic;\n        [SerializeField] private ResumeMusicEvent eventResumeMusic;\n\n        [Space] [TitleColor(\"Sfx Listening\", CustomColor.Orange, CustomColor.Bisque)] [SerializeField]\n        private PlaySfxEvent eventPlaySfx;\n\n        [SerializeField] private StopSfxEvent eventStopSfx;\n        [SerializeField] private PauseSfxEvent eventPauseSfx;\n        [SerializeField] private ResumeSfxEvent eventResumeSfx;\n        [SerializeField] private FinishSfxEvent eventFinishSfx;\n        [SerializeField] private StopAllSfxEvent eventStopAllSfx;\n\n        [Space] [TitleColor(\"AudioManager Settings\", CustomColor.DeepSkyBlue, CustomColor.Salmon)] [SerializeField]\n        private MusicVolumeChange musicVolume;\n\n        [SerializeField] SfxVolumeChange sfxVolume;\n\n        private SoundComponent music;\n\n        [ReadOnly, SerializeField] private List<SoundComponent> listCacheSfx = new List<SoundComponent>();\n\n        private int key = 0;\n\n        private void Awake()\n        {\n            if (isDontDestroyOnLoad)\n            {\n                DontDestroyOnLoad(this.gameObject);\n            }\n\n            sfxVolume.AddListener(OnSfxVolumeChanged);\n            musicVolume.AddListener(OnMusicVolumeChanged);\n        }\n\n        public override void OnEnable()\n        {\n            base.OnEnable();\n            eventPlaySfx.AddListener(PlaySfx);\n            eventStopSfx.AddListener(StopSfx);\n            eventFinishSfx.AddListener(FinishSfx);\n            eventResumeSfx.AddListener(ResumeSfx);\n            eventPauseSfx.AddListener(PauseSfx);\n            eventStopAllSfx.AddListener(StopAllSfx);\n\n            eventPlayMusic.AddListener(PlayMusic);\n            eventPauseMusic.AddListener(PauseMusic);\n            eventResumeMusic.AddListener(ResumeMusic);\n            eventStopMusic.AddListener(StopMusic);\n        }\n\n        public override void OnDisable()\n        {\n            base.OnDisable();\n            eventPlaySfx.RemoveListener(PlaySfx);\n            eventStopSfx.RemoveListener(StopSfx);\n            eventFinishSfx.RemoveListener(FinishSfx);\n            eventResumeSfx.RemoveListener(ResumeSfx);\n            eventPauseSfx.RemoveListener(PauseSfx);\n            eventStopAllSfx.RemoveListener(StopAllSfx);\n\n            eventPlayMusic.RemoveListener(PlayMusic);\n            eventPauseMusic.RemoveListener(PauseMusic);\n            eventResumeMusic.RemoveListener(ResumeMusic);\n            eventStopMusic.RemoveListener(StopMusic);\n        }\n\n        void OnMusicVolumeChanged(float volume)\n        {\n            if (music != null)\n            {\n                music.Volume = volume;\n            }\n        }\n\n        void OnSfxVolumeChanged(float volume)\n        {\n            for (var i = 0; i < listCacheSfx.Count; i++)\n            {\n                listCacheSfx[i].Volume = volume;\n            }\n        }\n\n        #region Sfx\n\n        private SoundCache PlaySfx(SoundData soundData)\n        {\n            var sfxComponent = soundComponentPrefab.Spawn(audioHolder);\n            sfxComponent.PlayAudioClip(soundData.GetAudioClip(), soundData.loop,\n                soundData.volume * sfxVolume.Value);\n            if (!soundData.loop) sfxComponent.OnCompleted += OnFinishPlayingAudio;\n            SoundCache soundCache = GetSoundCache(soundData);\n            sfxComponent.Key = key;\n            listCacheSfx.Add(sfxComponent);\n            return soundCache;\n        }\n\n        private void StopSfx(SoundCache soundCache)\n        {\n            var soundComponent = GetSoundComponent(soundCache);\n            if (soundComponent == null) return;\n            StopAndCleanAudioComponent(soundComponent);\n        }\n\n        private void PauseSfx(SoundCache soundCache)\n        {\n            var soundComponent = GetSoundComponent(soundCache);\n            if (soundComponent == null || !soundComponent.IsPlaying) return;\n            soundComponent.Pause();\n        }\n\n        private void ResumeSfx(SoundCache soundCache)\n        {\n            var soundComponent = GetSoundComponent(soundCache);\n            if (soundComponent == null || soundComponent.IsPlaying) return;\n            soundComponent.Resume();\n        }\n\n        private void FinishSfx(SoundCache soundCache)\n        {\n            var soundComponent = GetSoundComponent(soundCache);\n            if (soundComponent == null || !soundComponent.IsPlaying) return;\n            soundComponent.Finish();\n            soundComponent.OnCompleted += OnFinishPlayingAudio;\n        }\n\n        private void StopAllSfx()\n        {\n            var listTemp = listCacheSfx.ToList();\n            for (int i = 0; i < listTemp.Count; i++)\n            {\n                StopAndCleanAudioComponent(listTemp[i]);\n            }\n\n            listCacheSfx.Clear();\n            listTemp.Clear();\n\n            key = 0;\n        }\n\n        #endregion\n\n        #region Music\n\n        private void PlayMusic(SoundData soundData)\n        {\n            if (music == null || !music.IsPlaying)\n            {\n                music = soundComponentPrefab.Spawn(audioHolder);\n            }\n\n            music.FadePlayMusic(soundData.GetAudioClip(), soundData.loop, soundData.volume * musicVolume.Value,\n                soundData.isMusicFadeVolume, soundData.fadeOutDuration, soundData.fadeInDuration);\n            music.OnCompleted += StopAudioMusic;\n        }\n\n        private void StopMusic()\n        {\n            if (music != null && music.IsPlaying)\n            {\n                music.Stop();\n                music.gameObject.DeSpawn();\n            }\n        }\n\n        private void PauseMusic()\n        {\n            if (music != null && music.IsPlaying)\n            {\n                music.Pause();\n            }\n        }\n\n        private void ResumeMusic()\n        {\n            if (music != null && !music.IsPlaying)\n            {\n                music.Resume();\n            }\n        }\n\n        #endregion\n\n\n        void OnFinishPlayingAudio(SoundComponent soundComponent)\n        {\n            StopAndCleanAudioComponent(soundComponent);\n        }\n\n        void StopAndCleanAudioComponent(SoundComponent soundComponent)\n        {\n            if (!soundComponent.IsLooping)\n            {\n                soundComponent.OnCompleted -= OnFinishPlayingAudio;\n            }\n\n            soundComponent.Stop();\n            soundComponent.gameObject.DeSpawn();\n            if (listCacheSfx.Contains(soundComponent)) listCacheSfx.Remove(soundComponent);\n        }\n\n        void StopAudioMusic(SoundComponent soundComponent)\n        {\n            soundComponent.OnCompleted -= StopAudioMusic;\n            soundComponent.gameObject.DeSpawn();\n        }\n\n        SoundComponent GetSoundComponent(SoundCache soundCache)\n        {\n            if (soundCache == null) return null;\n            for (var i = 0; i < listCacheSfx.Count; i++)\n            {\n                if (soundCache.key == listCacheSfx[i].Key) return listCacheSfx[i];\n            }\n\n            return null;\n        }\n\n\n        SoundCache GetSoundCache(SoundData soundData)\n        {\n            key++;\n            return new SoundCache(key, soundData);\n        }\n\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            eventPlayMusic =\n                CreateAsset.CreateAndGetScriptableAsset<PlayMusicEvent>(\"/Audio/Music_Event\", \"play_music_event\",\n                    false);\n            eventPauseMusic =\n                CreateAsset.CreateAndGetScriptableAsset<PauseMusicEvent>(\"/Audio/Music_Event\", \"pause_music_event\",\n                    false);\n            eventResumeMusic = CreateAsset.CreateAndGetScriptableAsset<ResumeMusicEvent>(\"/Audio/Music_Event\",\n                \"resume_music_event\", false);\n            eventStopMusic =\n                CreateAsset.CreateAndGetScriptableAsset<StopMusicEvent>(\"/Audio/Music_Event\", \"stop_music_event\",\n                    false);\n            eventPlaySfx =\n                CreateAsset.CreateAndGetScriptableAsset<PlaySfxEvent>(\"/Audio/Sfx_Event\", \"play_sfx_event\", false);\n            eventPauseSfx =\n                CreateAsset.CreateAndGetScriptableAsset<PauseSfxEvent>(\"/Audio/Sfx_Event\", \"pause_sfx_event\", false);\n            eventFinishSfx =\n                CreateAsset.CreateAndGetScriptableAsset<FinishSfxEvent>(\"/Audio/Sfx_Event\", \"finish_sfx_event\", false);\n            eventResumeSfx =\n                CreateAsset.CreateAndGetScriptableAsset<ResumeSfxEvent>(\"/Audio/Sfx_Event\", \"resume_sfx_event\", false);\n            eventStopSfx =\n                CreateAsset.CreateAndGetScriptableAsset<StopSfxEvent>(\"/Audio/Sfx_Event\", \"stop_sfx_event\", false);\n            eventStopAllSfx =\n                CreateAsset.CreateAndGetScriptableAsset<StopAllSfxEvent>(\"/Audio/Sfx_Event\", \"stop_all_sfx_event\",\n                    false);\n            musicVolume =\n                CreateAsset.CreateAndGetScriptableAsset<MusicVolumeChange>(\"/Audio/Volume_Change\", \"music_volume\",\n                    false);\n            sfxVolume = CreateAsset.CreateAndGetScriptableAsset<SfxVolumeChange>(\"/Audio/Volume_Change\", \"sfx_volume\",\n                false);\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/AudioManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 82e25e7d80544a1d83bfd260713b1796\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23fb672e22185124e935486385bd367e, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/PauseMusicEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Music Event/Pause Music Event\", fileName = \"pause_music_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class PauseMusicEvent : EventNoParam\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/PauseMusicEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6afe7f83f7204cc4863081a953b272fd\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/PlayMusicEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Music Event/Play Music Event\", fileName = \"play_music_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class PlayMusicEvent : BaseEvent<SoundData>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/PlayMusicEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8a62aa8ea2ab43eda9340c8c4f73ef33\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/ResumeMusicEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Music Event/Resume Music Event\", fileName = \"resume_music_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class ResumeMusicEvent : EventNoParam\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/ResumeMusicEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0c8ea13bce9145d098ed6b23efa482fa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/StopMusicEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Music Event/Stop Music Event\", fileName = \"stop_music_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class StopMusicEvent : EventNoParam\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event/StopMusicEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3f802843e01846d5b770835f611fe93f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Music_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 5ecd74fd5ac547138187235af28e29ba\ntimeCreated: 1708586749"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/FinishSfxEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sfx Event/Finish Sfx Event\", fileName = \"finish_sfx_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class FinishSfxEvent : BaseEvent<SoundCache>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/FinishSfxEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dae25ae930684ca48408572b4079a12b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/PauseSfxEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sfx Event/Pause Sfx Event\", fileName = \"pause_sfx_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class PauseSfxEvent : BaseEvent<SoundCache>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/PauseSfxEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d6cf60657a4f4fe48c1e7a836cec9746\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/PlaySfxEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sfx Event/Play Sfx Event\", fileName = \"play_sfx_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class PlaySfxEvent : BaseEvent<SoundData, SoundCache>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/PlaySfxEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 797820d819bc40e585a07f1deeb9d3ce\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/ResumeSfxEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sfx Event/Resume Sfx Event\", fileName = \"resume_sfx_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class ResumeSfxEvent : BaseEvent<SoundCache>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/ResumeSfxEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 69920a2e5b00475c8b3ef12220c0d857\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/StopAllSfxEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sfx Event/Stop All Sfx Event\", fileName = \"stop_all_sfx_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class StopAllSfxEvent : EventNoParam\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/StopAllSfxEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 93775b3394ad4d82bdc5ccec6da042a8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/StopSfxEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sfx Event/Stop Sfx Event\", fileName = \"stop_sfx_event\")]\n    [EditorIcon(\"scriptable_audio\")]\n    public class StopSfxEvent : BaseEvent<SoundCache>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event/StopSfxEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d6777856ee46403eb05f154212201213\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f6fa313956d229647ad5911f1b5d081a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Sfx_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 9f13899b470548ada5efd57120f05db4\ntimeCreated: 1708586378"
  },
  {
    "path": "VirtueSky/Audio/Runtime/SoundCache.cs",
    "content": "using System;\n\nnamespace VirtueSky.Audio\n{\n    [Serializable]\n    public class SoundCache\n    {\n        internal int key;\n        internal SoundData soundData;\n\n        public SoundCache(int _key, SoundData _soundData)\n        {\n            key = _key;\n            soundData = _soundData;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/SoundCache.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ed6986a4d9b4a339782b0aed0f5a2a5\ntimeCreated: 1715228780"
  },
  {
    "path": "VirtueSky/Audio/Runtime/SoundComponent.cs",
    "content": "﻿using System;\nusing PrimeTween;\nusing UnityEngine;\nusing UnityEngine.Events;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Audio\n{\n    [RequireComponent(typeof(AudioSource))]\n    [EditorIcon(\"icon_csharp\")]\n    public class SoundComponent : CacheComponent<AudioSource>\n    {\n        [ReadOnly, SerializeField] private int key;\n        public event UnityAction<SoundComponent> OnCompleted;\n        public event UnityAction<SoundComponent> OnPaused;\n        public event UnityAction<SoundComponent> OnResumed;\n        public event UnityAction<SoundComponent> OnStopped;\n\n        public AudioClip GetClip => component.clip;\n        public bool IsPlaying => component.isPlaying;\n        public bool IsLooping => component.loop;\n\n        public float Volume\n        {\n            get => component.volume;\n            set => component.volume = value;\n        }\n\n        public int Key\n        {\n            get => key;\n            set => key = value;\n        }\n\n        private void Awake()\n        {\n            component.playOnAwake = false;\n        }\n\n        internal void PlayAudioClip(AudioClip audioClip, bool isLooping, float volume)\n        {\n            if (audioClip == null)\n            {\n                Debug.LogError($\"AudioClip is null\");\n                return;\n            }\n\n            component.clip = audioClip;\n            component.loop = isLooping;\n            component.volume = volume;\n            component.time = 0;\n            component.Play();\n            if (!isLooping)\n            {\n                App.Delay(this, audioClip.length, OnCompletedInvoke);\n            }\n        }\n\n        void FadeInVolumeMusic(AudioClip audioClip, bool isLooping, float endValue, float duration)\n        {\n            PlayAudioClip(audioClip, isLooping, 0);\n            Tween.AudioVolume(component, endValue, duration);\n        }\n\n        void FadeOutVolumeMusic(float duration, Action fadeCompleted)\n        {\n            Tween.AudioVolume(component, 0, duration).OnComplete(fadeCompleted);\n        }\n\n\n        internal void Resume()\n        {\n            OnResumed?.Invoke(this);\n            component.UnPause();\n        }\n\n        internal void Pause()\n        {\n            OnPaused?.Invoke(this);\n            component.Pause();\n        }\n\n        internal void Stop()\n        {\n            OnStopped?.Invoke(this);\n            component.Stop();\n        }\n\n        internal void Finish()\n        {\n            if (!component.loop) return;\n            component.loop = false;\n            float remainingTime = component.clip.length - component.time;\n            App.Delay(this, remainingTime, OnCompletedInvoke);\n        }\n\n        internal void FadePlayMusic(AudioClip audioClip, bool isLooping, float volume, bool isMusicFadeVolume,\n            float durationOut,\n            float durationIn)\n        {\n            if (isMusicFadeVolume && volume != 0)\n            {\n                if (component.isPlaying)\n                {\n                    FadeOutVolumeMusic(durationOut,\n                        () => { FadeInVolumeMusic(audioClip, isLooping, volume, durationIn); });\n                }\n                else\n                {\n                    FadeInVolumeMusic(audioClip, isLooping, volume, durationIn);\n                }\n            }\n            else\n            {\n                PlayAudioClip(audioClip, isLooping, volume);\n            }\n        }\n\n        private void OnCompletedInvoke()\n        {\n            OnCompleted?.Invoke(this);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/SoundComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 553b54cd20a24345a93a5afbb0dea5e0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/SoundData.cs",
    "content": "﻿using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Core;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Sound Data\", fileName = \"sound_data\")]\n    [EditorIcon(\"scriptable_audioclip\")]\n    public class SoundData : BaseSO\n    {\n        public enum GetType\n        {\n            Random,\n            Sequence\n        }\n\n        [Space] public bool loop = false;\n        [Range(0f, 1f)] public float volume = 1;\n\n        [Header(\"Fade Volume - Only Music\"), Tooltip(\"Only Music Background\")]\n        public bool isMusicFadeVolume = false;\n\n        [ShowIf(nameof(isMusicFadeVolume), true)]\n        public float fadeInDuration = .5f;\n\n        [ShowIf(nameof(isMusicFadeVolume), true)]\n        public float fadeOutDuration = .5f;\n\n        [Space] public GetType getType = GetType.Random;\n        [SerializeField] private List<AudioClip> audioClips;\n\n        private int sequenceIndex = 0;\n        public int NumberOfAudioClips => audioClips.Count;\n        public List<AudioClip> AudioClips() => audioClips;\n\n        public AudioClip GetAudioClip()\n        {\n            if (audioClips.Count > 0)\n            {\n                switch (getType)\n                {\n                    case GetType.Random:\n                        return audioClips[Random.Range(0, audioClips.Count)];\n                    case GetType.Sequence:\n                        var clip = audioClips[sequenceIndex];\n                        if (sequenceIndex < audioClips.Count - 1)\n                        {\n                            sequenceIndex++;\n                        }\n                        else\n                        {\n                            sequenceIndex = 0;\n                        }\n\n                        return clip;\n                }\n            }\n\n            return null;\n        }\n\n        public void AddAudioClip(AudioClip audioClip)\n        {\n            audioClips.Add(audioClip);\n        }\n\n        public void AddAudioClips(List<AudioClip> clips)\n        {\n            audioClips.Adds(clips);\n        }\n\n        public void AddAudioClips(AudioClip[] clips)\n        {\n            audioClips.Adds(clips);\n        }\n\n        public void ClearAudioClips()\n        {\n            if (audioClips.IsNullOrEmpty()) return;\n            audioClips.Clear();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/SoundData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 474a3bbd13954ce3abb782ceec59e692\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 3db558bebc410834889c3cdb93ca89b1, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Volume_Variable/MusicVolumeChange.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Volume Change Variable/Music Volume Change\",\n        fileName = \"music_volume\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class MusicVolumeChange : FloatVariable\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Volume_Variable/MusicVolumeChange.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 04035b55bf6d4056848898fcc6217886\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Volume_Variable/SfxVolumeChange.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.Audio\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Audio/Volume Change Variable/Sfx Volume Change\",\n        fileName = \"sfx_volume\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class SfxVolumeChange : FloatVariable\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Volume_Variable/SfxVolumeChange.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dbff0f3c083045338776b184bac0261a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime/Volume_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 3f73d8c16cec4ccc88ce2afd329699ec\ntimeCreated: 1708587464"
  },
  {
    "path": "VirtueSky/Audio/Runtime/virtuesky.sunflower.audio.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Audio\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:35d694408290717499b3838802212c7f\",\n        \"GUID:ce8c6e3f188ed064f933ef35b46bf8bd\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:80ecb87cae9c44d19824e70ea7229748\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:540154dd0c5ed9a4dbbe695c402232fb\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Audio/Runtime/virtuesky.sunflower.audio.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 2ba9ab3e4292d6e4b81f0022dc854eee\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 2b3ed978f9e1d42e1ab7b5ee2ed548af\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Audio.meta",
    "content": "fileFormatVersion: 2\nguid: 4b793d0ec10139c4ebef842e4332fc00\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Editor/ButtomCustomEditor.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UIButton;\nusing VirtueSky.UtilsEditor;\n\n#if UNITY_EDITOR\n[CustomEditor(typeof(ButtonCustom), true)]\n[CanEditMultipleObjects]\npublic class ButtomCustomEditor : UnityEditor.UI.ButtonEditor\n{\n    private ButtonCustom _buttonCustom;\n    private SerializedProperty _isMotion;\n    private SerializedProperty _ease;\n    private SerializedProperty _scale;\n    private SerializedProperty _easingTypes;\n    private SerializedProperty _clickButtonEvent;\n    private SerializedProperty _isShrugOver;\n    private SerializedProperty _timeShrug;\n    private SerializedProperty _strength;\n    private SerializedProperty _useSoundFx;\n    private SerializedProperty _playSfxEvent;\n    private SerializedProperty _soundDataClickButton;\n\n    protected override void OnEnable()\n    {\n        base.OnEnable();\n        _buttonCustom = target as ButtonCustom;\n        _isMotion = serializedObject.FindProperty(\"isMotion\");\n        _easingTypes = serializedObject.FindProperty(\"easingTypes\");\n        _scale = serializedObject.FindProperty(\"scale\");\n        _clickButtonEvent = serializedObject.FindProperty(\"clickButtonEvent\");\n        _isShrugOver = serializedObject.FindProperty(\"isShrugOver\");\n        _timeShrug = serializedObject.FindProperty(\"timeShrug\");\n        _strength = serializedObject.FindProperty(\"strength\");\n        _useSoundFx = serializedObject.FindProperty(\"useSoundFx\");\n        _playSfxEvent = serializedObject.FindProperty(\"playSfxEvent\");\n        _soundDataClickButton = serializedObject.FindProperty(\"soundDataClickButton\");\n    }\n\n    public override void OnInspectorGUI()\n    {\n        base.OnInspectorGUI();\n        serializedObject.Update();\n        GUILayout.Space(5);\n        GUILayout.Space(5);\n        Uniform.DrawGroupFoldout(\"button_custom_setting\", \"Setting\", () => DrawSetting(), true);\n\n        serializedObject.ApplyModifiedProperties();\n        serializedObject.Update();\n    }\n\n    void DrawSetting()\n    {\n        EditorGUILayout.BeginHorizontal();\n        EditorGUILayout.PropertyField(_clickButtonEvent);\n\n        GUILayout.Space(2);\n        if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n        {\n            _buttonCustom.GetClickButtonEvent();\n        }\n\n        EditorGUILayout.EndHorizontal();\n\n        EditorGUILayout.PropertyField(_isMotion);\n        if (_isMotion.boolValue)\n        {\n            EditorGUILayout.PropertyField(_easingTypes);\n            EditorGUILayout.PropertyField(_scale);\n            EditorGUILayout.PropertyField(_isShrugOver);\n            if (_isShrugOver.boolValue)\n            {\n                EditorGUILayout.PropertyField(_timeShrug);\n                EditorGUILayout.PropertyField(_strength);\n            }\n        }\n\n        GUILayout.Space(5);\n        EditorGUILayout.PropertyField(_useSoundFx);\n        if (_useSoundFx.boolValue)\n        {\n            EditorGUILayout.PropertyField(_playSfxEvent);\n            EditorGUILayout.PropertyField(_soundDataClickButton);\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Button/Editor/ButtomCustomEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dec209bc2c357084bb099281e69d88e1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Editor/Virtuesky.Sunflower.Button.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Button.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:18d115b3ed531e149a91cb3e69e202c5\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Button/Editor/Virtuesky.Sunflower.Button.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: a4d70e152f59a2b4788851c89dfa3ea8\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 5f2fea8cee7f953469bbe7cff4d9b443\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonCustom.cs",
    "content": "using PrimeTween;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.EventSystems;\nusing VirtueSky.Audio;\nusing VirtueSky.Inspector;\nusing VirtueSky.Events;\nusing VirtueSky.Misc;\nusing VirtueSky.Utils;\nusing Button = UnityEngine.UI.Button;\n\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\n\n\nnamespace VirtueSky.UIButton\n{\n    [EditorIcon(\"icon_button\")]\n    public abstract class ButtonCustom : Button\n    {\n        public ClickButtonEvent clickButtonEvent;\n\n        [HeaderLine(\"Motion\", false, CustomColor.Yellow, CustomColor.Orange)] [SerializeField]\n        private bool isMotion = true;\n\n        [SerializeField] private Ease easingTypes = Ease.OutQuint;\n\n        [SerializeField] private float scale = 0.9f;\n        [SerializeField] private bool isShrugOver;\n        [SerializeField] private float timeShrug = .2f;\n        [SerializeField] private float strength = .2f;\n\n        [HeaderLine(\"Sound Fx Click Button\", false, CustomColor.Aqua, CustomColor.Salmon)] [SerializeField]\n        private bool useSoundFx;\n\n        [SerializeField] private PlaySfxEvent playSfxEvent;\n        [SerializeField] private SoundData soundDataClickButton;\n\n        Vector3 originScale = Vector3.one;\n        private bool canShrug = true;\n        private Tween _tween;\n\n        protected override void OnEnable()\n        {\n            base.OnEnable();\n            originScale = transform.localScale;\n        }\n\n        protected override void OnDisable()\n        {\n            base.OnDisable();\n            ResetScale();\n        }\n\n\n        public override void OnPointerDown(PointerEventData eventData)\n        {\n            base.OnPointerDown(eventData);\n            DoScale();\n            if (useSoundFx)\n            {\n                soundDataClickButton.PlaySfx(playSfxEvent);\n            }\n\n            if (clickButtonEvent != null)\n            {\n                clickButtonEvent.Raise();\n            }\n            else\n            {\n                Debug.Log($\"Click button event ({gameObject.name}) null\");\n            }\n        }\n\n\n        public override void OnPointerUp(PointerEventData eventData)\n        {\n            base.OnPointerUp(eventData);\n            ResetScale();\n        }\n\n        public override void OnPointerExit(PointerEventData eventData)\n        {\n            base.OnPointerExit(eventData);\n            Shrug();\n        }\n\n        void DoScale()\n        {\n            if (isMotion)\n            {\n                _tween = Tween.Scale(transform, originScale * scale, .15f, easingTypes);\n            }\n        }\n\n        void Shrug()\n        {\n            if (isMotion && isShrugOver && canShrug)\n            {\n                canShrug = false;\n                if (isMotion && isShrugOver)\n                {\n                    transform.Shrug(timeShrug, strength, Ease.OutQuad, () => { canShrug = true; });\n                }\n            }\n        }\n\n        void ResetScale()\n        {\n            if (isMotion)\n            {\n                _tween.Stop();\n                transform.localScale = originScale;\n            }\n        }\n#if UNITY_EDITOR\n        protected override void Reset()\n        {\n            base.Reset();\n            GetClickButtonEvent();\n            playSfxEvent =\n                CreateAsset.CreateAndGetScriptableAsset<PlaySfxEvent>(\"/Audio/Sfx_Event\", \"play_sfx_event\", false);\n        }\n\n        public void GetClickButtonEvent()\n        {\n            clickButtonEvent = CreateAsset.CreateAndGetScriptableAsset<ClickButtonEvent>(\"/Event\");\n            EditorUtility.SetDirty(this);\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonCustom.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 77a8a8f178e747a4b39b894fbf66604c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonTMP.cs",
    "content": "﻿using TMPro;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.UIButton\n{\n    [RequireComponent(typeof(TextMeshProUGUI))]\n    [EditorIcon(\"icon_button\")]\n    public class ButtonTMP : ButtonCustom\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonTMP.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ba973a132e6c491880e5a1aae7803eea\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonText.cs",
    "content": "﻿using UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.UIButton\n{\n    [RequireComponent(typeof(Text))]\n    [EditorIcon(\"icon_button\")]\n    public class ButtonText : ButtonCustom\n    {\n#if UNITY_EDITOR\n        protected override void Reset()\n        {\n            base.Reset();\n            var label = GetComponent<Text>();\n            label.color = new Color(255, 255, 255, 255);\n            label.text = \"Button_Text\";\n            label.fontSize = 50;\n            label.alignment = TextAnchor.MiddleCenter;\n            var rect = GetComponent<RectTransform>();\n            rect.localScale = Vector3.one;\n            rect.position = Vector3.zero;\n            rect.sizeDelta = new Vector2(300, 80);\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonText.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6e5d3bd7e9f844e5ad509941360c6c44\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonUI.cs",
    "content": "using UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.UIButton\n{\n    [RequireComponent(typeof(Image))]\n    [EditorIcon(\"icon_button\")]\n    public class ButtonUI : ButtonCustom\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonUI.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7b68f598bc9541c7b9f48bf2b23de502\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonUI_TMP.cs",
    "content": "﻿using TMPro;\nusing UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.UIButton\n{\n    [RequireComponent(typeof(Image))]\n    [EditorIcon(\"icon_button\")]\n    public class ButtonUI_TMP : ButtonCustom\n    {\n#if UNITY_EDITOR\n        protected override void Reset()\n        {\n            base.Reset();\n            var label = new GameObject(\"Label\");\n            label.transform.SetParent(this.transform);\n            var text = label.AddComponent<TextMeshProUGUI>();\n            text.color = new Color(0, 0, 0, 255);\n            text.text = \"Label Button\";\n            text.horizontalAlignment = HorizontalAlignmentOptions.Center;\n            text.verticalAlignment = VerticalAlignmentOptions.Middle;\n            var rectTransform = label.GetComponent<RectTransform>();\n            var rectTransformParent = GetComponent<RectTransform>();\n            rectTransform.localScale = rectTransformParent.localScale;\n            rectTransform.position = rectTransformParent.position;\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonUI_TMP.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c66092e8fe574c688a4c6e65b36bfd41\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonUI_Text.cs",
    "content": "﻿using UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.UIButton\n{\n    [RequireComponent(typeof(Image))]\n    [EditorIcon(\"icon_button\")]\n    public class ButtonUI_Text : ButtonCustom\n    {\n#if UNITY_EDITOR\n        protected override void Reset()\n        {\n            base.Reset();\n            var labelObj = new GameObject(\"Label\");\n            labelObj.transform.SetParent(transform);\n            var label = labelObj.AddComponent<Text>();\n            label.color = new Color(0, 0, 0, 255);\n            label.text = \"Button_Text\";\n            label.fontSize = 50;\n            label.alignment = TextAnchor.MiddleCenter;\n            var rect = labelObj.GetComponent<RectTransform>();\n            var rectParent = GetComponent<RectTransform>();\n            rect.localScale = rectParent.localScale;\n            rect.position = rectParent.position;\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/ButtonUI_Text.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9d99d72c109e467c8853cf4074e0adc7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 64bffa989a83702458593189b3a27b57, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime/Virtuesky.Sunflower.Button.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Button\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:6055be8ebefd69e48b49212b09b47b2f\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:80ecb87cae9c44d19824e70ea7229748\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:2ba9ab3e4292d6e4b81f0022dc854eee\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [\n        {\n            \"name\": \"com.unity.textmeshpro\",\n            \"expression\": \"\",\n            \"define\": \"\"\n        }\n    ],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Button/Runtime/Virtuesky.Sunflower.Button.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 18d115b3ed531e149a91cb3e69e202c5\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 38260143c92a707439a61a3aece91153\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Button.meta",
    "content": "fileFormatVersion: 2\nguid: f826083e0d994d14ab3a31609950179e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/AnimancerComponent/HandleAnimancerComponent.cs",
    "content": "#if VIRTUESKY_ANIMANCER\nusing Animancer;\nusing System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(AnimancerComponent))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class HandleAnimancerComponent : MonoBehaviour\n    {\n        [SerializeField] private AnimancerComponent animancerComponent;\n        public AnimancerComponent AnimancerComponent => animancerComponent;\n\n        public bool IsPlaying(ClipTransition clip) => animancerComponent.IsPlaying(clip);\n\n        public void PlayAnim(ClipTransition clip, Action _endAnim = null, float _durationFade = .2f,\n            bool isCheckPlayingClip = true, FadeMode mode = default, object _owner = null)\n        {\n            if (isCheckPlayingClip)\n            {\n                if (!animancerComponent.IsPlaying(clip))\n                {\n                    Handle();\n                }\n            }\n            else\n            {\n                Handle();\n            }\n\n            void Handle()\n            {\n                var state = animancerComponent.Play(clip, clip.Clip.length * _durationFade, mode);\n                if (_endAnim != null)\n                {\n                    object owner = _owner ?? animancerComponent;\n                    state.Events(owner).OnEnd += OnEndAnim;\n\n                    void OnEndAnim()\n                    {\n                        state.Events(owner).OnEnd -= OnEndAnim;\n                        _endAnim?.Invoke();\n                    }\n                }\n            }\n        }\n\n        // Freeze a single animation on its current frame:\n        public void PauseClip(ClipTransition clip)\n        {\n            animancerComponent.States[clip].IsPlaying = false;\n        }\n\n        // Freeze all animations on their current frame:\n        public void PauseAll()\n        {\n            animancerComponent.Graph.PauseGraph();\n        }\n\n        // Stop a single animation from affecting the character and rewind it to the start:\n        public void StopClip(ClipTransition clip)\n        {\n            animancerComponent.Stop(clip);\n\n            // Or you can call it on the state directly:\n            var state = animancerComponent.States[clip];\n            state.Stop();\n        }\n\n        // Stop all animations from affecting the character and rewind them to the start:\n        public void StopAll()\n        {\n            animancerComponent.Stop();\n        }\n\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            if (animancerComponent == null)\n            {\n                animancerComponent = GetComponent<AnimancerComponent>();\n            }\n        }\n#endif\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Component/AnimancerComponent/HandleAnimancerComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b50203cff2b74e849a2fe7c6bb333776\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/AnimancerComponent.meta",
    "content": "fileFormatVersion: 2\nguid: 5feb8e7c264a6744baac771c57a700af\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/BounceComponent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class BounceComponent : BaseMono\n    {\n        [Header(\"Attributes\")] public bool isRotate = false;\n\n        public float degreesPerSecond = 15.0f;\n        public float amplitude = 5f;\n        public float frequency = 1f;\n\n        private Vector3 _posOffset;\n        private Vector3 _tempPos;\n        private bool isBounce = true;\n\n        public override void OnEnable()\n        {\n            base.OnEnable();\n            isBounce = true;\n            _posOffset = transform.localPosition;\n        }\n\n        public void Pause()\n        {\n            isBounce = false;\n        }\n\n        public void Resume()\n        {\n            isBounce = true;\n        }\n\n        public override void FixedTick()\n        {\n            base.FixedTick();\n            if (isBounce)\n            {\n                if (isRotate)\n                {\n                    transform.Rotate(new Vector3(0f, Time.deltaTime * degreesPerSecond, 0f), Space.World);\n                }\n\n                _tempPos = _posOffset;\n                _tempPos.y += Mathf.Sin(Time.fixedTime * Mathf.PI * frequency) * amplitude;\n\n                transform.localPosition = _tempPos;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/BounceComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3738ba9d850a44feadde2a3c37c3df41\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/Buoyancy2DComponent.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(Rigidbody2D))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class Buoyancy2DComponent : CacheComponent<Rigidbody2D>\n    {\n        public Transform[] floaters;\n        public float underWaterDrag = 3f;\n        public float underWaterAngularDrag = 1f;\n        public float airDrag = 0f;\n        public float airAngularDrag = 0.05f;\n        public float floatingPower = 15f;\n        public float waterHeight = 0f;\n        bool Underwater;\n\n        int floatersUnderWater;\n\n\n        // Update is called once per frame\n        public override void FixedTick()\n        {\n            base.FixedTick();\n            floatersUnderWater = 0;\n            for (int i = 0; i < floaters.Length; i++)\n            {\n                float diff = floaters[i].position.y - waterHeight;\n                if (diff < 0)\n                {\n                    component.AddForceAtPosition(Vector3.up * floatingPower * Mathf.Abs(diff), floaters[i].position,\n                        ForceMode2D.Force);\n                    floatersUnderWater += 1;\n                    if (!Underwater)\n                    {\n                        Underwater = true;\n                        SwitchState(true);\n                    }\n                }\n            }\n\n            if (Underwater && floatersUnderWater == 0)\n            {\n                Underwater = false;\n                SwitchState(false);\n            }\n        }\n\n        void SwitchState(bool isUnderwater)\n        {\n#if UNITY_6000_0_OR_NEWER\n            component.linearDamping = isUnderwater ? underWaterDrag : airDrag;\n            component.angularDamping = isUnderwater ? underWaterAngularDrag : airAngularDrag;\n#else\n            component.drag = isUnderwater ? underWaterDrag : airDrag;\n            component.angularDrag = isUnderwater ? underWaterAngularDrag : airAngularDrag;\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/Buoyancy2DComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 633b7fa9831f4185b49828dffeb5ae0d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/BuoyancyComponent.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(Rigidbody))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class BuoyancyComponent : CacheComponent<Rigidbody>\n    {\n        public Transform[] floaters;\n        public float underWaterDrag = 3f;\n        public float underWaterAngularDrag = 1f;\n        public float airDrag = 0f;\n        public float airAngularDrag = 0.05f;\n        public float floatingPower = 15f;\n        public float waterHeight = 0f;\n        bool Underwater;\n\n        int floatersUnderWater;\n\n\n        // Update is called once per frame\n        public override void FixedTick()\n        {\n            base.FixedTick();\n            floatersUnderWater = 0;\n            for (int i = 0; i < floaters.Length; i++)\n            {\n                float diff = floaters[i].position.y - waterHeight;\n                if (diff < 0)\n                {\n                    component.AddForceAtPosition(Vector3.up * floatingPower * Mathf.Abs(diff), floaters[i].position,\n                        ForceMode.Force);\n                    floatersUnderWater += 1;\n                    if (!Underwater)\n                    {\n                        Underwater = true;\n                        SwitchState(true);\n                    }\n                }\n            }\n\n            if (Underwater && floatersUnderWater == 0)\n            {\n                Underwater = false;\n                SwitchState(false);\n            }\n        }\n\n        void SwitchState(bool isUnderwater)\n        {\n#if UNITY_6000_0_OR_NEWER\n            component.linearDamping = isUnderwater ? underWaterDrag : airDrag;\n            component.angularDamping = isUnderwater ? underWaterAngularDrag : airAngularDrag;\n#else\n            component.drag = isUnderwater ? underWaterDrag : airDrag;\n            component.angularDrag = isUnderwater ? underWaterAngularDrag : airAngularDrag;\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/BuoyancyComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 638f3f3b2ea44398921d0a90743d5882\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/EffectAppearComponent.cs",
    "content": "using UnityEngine;\nusing PrimeTween;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class EffectAppearComponent : BaseMono\n    {\n        public float delay = 0.1f;\n        [Range(0, 2f)] public float TimeScale = .7f;\n        public Ease ease = Ease.OutBack;\n        public Vector3 fromScale = new Vector3(.5f, .5f, .5f);\n        private Vector3 CurrentScale;\n        private Tween _tween;\n\n        public void Awake()\n        {\n            CurrentScale = transform.localScale;\n        }\n\n        public void OnEnable()\n        {\n            transform.localScale = fromScale;\n            App.Delay(this, delay, DoEffect);\n        }\n\n        public void DoEffect()\n        {\n            if (!gameObject.activeInHierarchy) return;\n            _tween = Tween.Scale(transform, CurrentScale, TimeScale, ease).OnComplete(() => { _tween.Stop(); }, false);\n        }\n\n        public override void OnDisable()\n        {\n            base.OnDisable();\n            _tween.Stop();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/EffectAppearComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8d6d71043917f4558833eb085b54db75\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/EffectZoomInOutComponent.cs",
    "content": "﻿using PrimeTween;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class EffectZoomInOutComponent : BaseMono\n    {\n        public bool playOnAwake = true;\n        [Range(0, 2f)] public float timeDelay;\n        [Range(0, 2f)] public float offsetScale = .1f;\n        [Range(0, 2f)] public float timeScale = .7f;\n        public Ease ease = Ease.Linear;\n        private Vector3 currentScale;\n        private Tween tween;\n        private bool isBreak = false;\n\n        public void Awake()\n        {\n            currentScale = transform.localScale;\n        }\n\n        public void OnEnable()\n        {\n            if (playOnAwake)\n            {\n                Play();\n            }\n        }\n\n        private void OnDisable()\n        {\n            tween.Stop();\n        }\n\n        public void Stop()\n        {\n            isBreak = true;\n            tween.Stop();\n        }\n\n        public void Play()\n        {\n            isBreak = false;\n            DoEffect(offsetScale, false);\n        }\n\n        public void DoEffect(float offsetScale, bool delay)\n        {\n            if (!gameObject.activeInHierarchy) return;\n            if (isBreak) return;\n            App.Delay(this, timeDelay * (delay ? 1 : 0),\n                () =>\n                {\n                    tween = transform.Scale(\n                            new Vector3(currentScale.x + offsetScale, currentScale.y + offsetScale,\n                                currentScale.z + offsetScale), timeScale, ease)\n                        .OnComplete(() => { DoEffect(-offsetScale, !delay); }, false);\n                });\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/EffectZoomInOutComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3ade0ecb53764967a07ba5247a582386\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/FollowTargetComponent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class FollowTargetComponent : BaseMono\n    {\n        [Tooltip(\"if currentTrans is null, then currentTrans will be set up with the current game object\"),\n         SerializeField]\n        private Transform currentTrans;\n\n        [Space, SerializeField] private Transform targetTrans;\n        [SerializeField] private bool useOffsetTrans = true;\n\n        [ShowIf(nameof(useOffsetTrans), true), ReadOnly, SerializeField]\n        private Vector3 offsetTrans;\n\n        [Space, SerializeField] private DirectionFollowTarget directionFollowTarget;\n        [Space, SerializeField] private TypeFollowTarget typeFollowTarget;\n\n        [Tooltip(\"Value used to interpolate between target and this object\"),\n         ShowIf(nameof(typeFollowTarget), TypeFollowTarget.Lerp), SerializeField]\n        private float interpolateValue = 0.05f;\n\n        [Tooltip(\"The current velocity, this value is modified by the function every time you call it.\"),\n         ShowIf(nameof(typeFollowTarget), TypeFollowTarget.SmoothDamp), SerializeField]\n        private Vector3 currentVelocity = Vector3.zero;\n\n        [Tooltip(\n             \"Approximately the time it will take to reach the target. A smaller value will reach the target faster.\"),\n         ShowIf(nameof(typeFollowTarget), TypeFollowTarget.SmoothDamp), SerializeField]\n        private float smoothTime = 0.05f;\n\n        [Tooltip(\"Optionally allows you to clamp the maximum speed.\"),\n         ShowIf(nameof(typeFollowTarget), TypeFollowTarget.SmoothDamp), SerializeField]\n        private float maxSpeed = Mathf.Infinity;\n\n        public Transform TargetTransform\n        {\n            get => targetTrans;\n            set => targetTrans = value;\n        }\n\n        public Vector3 OffsetTrans\n        {\n            get => offsetTrans;\n            set => offsetTrans = value;\n        }\n\n        public DirectionFollowTarget DirectionFollowTarget\n        {\n            get => directionFollowTarget;\n            set => directionFollowTarget = value;\n        }\n\n        public TypeFollowTarget TypeFollowTarget\n        {\n            get => typeFollowTarget;\n            set => typeFollowTarget = value;\n        }\n\n        public float InterpolateValue\n        {\n            get => interpolateValue;\n            set => interpolateValue = value;\n        }\n\n        public Vector3 CurrentVelocity\n        {\n            get => currentVelocity;\n            set => currentVelocity = value;\n        }\n\n        public float SmoothTime\n        {\n            get => smoothTime;\n            set => smoothTime = value;\n        }\n\n        public float MaxSpeed\n        {\n            get => maxSpeed;\n            set => maxSpeed = value;\n        }\n\n        private void Awake()\n        {\n            if (currentTrans == null)\n            {\n                currentTrans = gameObject.transform;\n            }\n\n            offsetTrans = useOffsetTrans ? currentTrans.position - targetTrans.position : Vector3.zero;\n        }\n\n        public void SetTarget(Transform t)\n        {\n            targetTrans = t;\n        }\n\n        public void SetDirectionFollowTarget(DirectionFollowTarget d)\n        {\n            directionFollowTarget = d;\n        }\n\n        public void SetTypeFollowTarget(TypeFollowTarget t)\n        {\n            typeFollowTarget = t;\n        }\n\n        public override void LateTick()\n        {\n            base.LateTick();\n            switch (typeFollowTarget)\n            {\n                case TypeFollowTarget.SetPosition:\n                    HandleSetPos();\n                    break;\n                case TypeFollowTarget.Lerp:\n                    HandleLerp();\n                    break;\n                case TypeFollowTarget.SmoothDamp:\n                    HandleSmoothDamp();\n                    break;\n            }\n        }\n\n        private void HandleSetPos()\n        {\n            Vector3 targetPos = targetTrans.position + offsetTrans;\n            switch (directionFollowTarget)\n            {\n                case DirectionFollowTarget.XYZ:\n                    currentTrans.SetPosition(targetPos);\n                    break;\n                case DirectionFollowTarget.XY:\n                    currentTrans.SetPositionXY(targetPos);\n                    break;\n                case DirectionFollowTarget.XZ:\n                    currentTrans.SetPositionXZ(targetPos);\n                    break;\n                case DirectionFollowTarget.YZ:\n                    currentTrans.SetPositionYZ(targetPos);\n                    break;\n                case DirectionFollowTarget.X:\n                    currentTrans.SetPositionX(targetPos.x);\n                    break;\n                case DirectionFollowTarget.Y:\n                    currentTrans.SetPositionY(targetPos.y);\n                    break;\n                case DirectionFollowTarget.Z:\n                    currentTrans.SetPositionZ(targetPos.y);\n                    break;\n            }\n        }\n\n        private void HandleLerp()\n        {\n            Vector3 interpolateVector3 = Vector3.Lerp(currentTrans.position, targetTrans.position + offsetTrans,\n                interpolateValue);\n            switch (directionFollowTarget)\n            {\n                case DirectionFollowTarget.XYZ:\n                    currentTrans.SetPosition(interpolateVector3);\n                    break;\n                case DirectionFollowTarget.XY:\n                    currentTrans.SetPositionXY(interpolateVector3);\n                    break;\n                case DirectionFollowTarget.XZ:\n                    currentTrans.SetPositionXZ(interpolateVector3);\n                    break;\n                case DirectionFollowTarget.YZ:\n                    currentTrans.SetPositionYZ(interpolateVector3);\n                    break;\n                case DirectionFollowTarget.X:\n                    currentTrans.SetPositionX(interpolateVector3.x);\n                    break;\n                case DirectionFollowTarget.Y:\n                    currentTrans.SetPositionY(interpolateVector3.y);\n                    break;\n                case DirectionFollowTarget.Z:\n                    currentTrans.SetPositionZ(interpolateVector3.z);\n                    break;\n            }\n        }\n\n        private void HandleSmoothDamp()\n        {\n            Vector3 smoothDampVector3 = Vector3.SmoothDamp(currentTrans.position, targetTrans.position + offsetTrans,\n                ref currentVelocity, smoothTime, maxSpeed);\n            switch (directionFollowTarget)\n            {\n                case DirectionFollowTarget.XYZ:\n                    currentTrans.SetPosition(smoothDampVector3);\n                    break;\n                case DirectionFollowTarget.XY:\n                    currentTrans.SetPositionXY(smoothDampVector3);\n                    break;\n                case DirectionFollowTarget.XZ:\n                    currentTrans.SetPositionXZ(smoothDampVector3);\n                    break;\n                case DirectionFollowTarget.YZ:\n                    currentTrans.SetPositionYZ(smoothDampVector3);\n                    break;\n                case DirectionFollowTarget.X:\n                    currentTrans.SetPositionX(smoothDampVector3.x);\n                    break;\n                case DirectionFollowTarget.Y:\n                    currentTrans.SetPositionY(smoothDampVector3.y);\n                    break;\n                case DirectionFollowTarget.Z:\n                    currentTrans.SetPositionZ(smoothDampVector3.z);\n                    break;\n            }\n        }\n    }\n\n    public enum DirectionFollowTarget\n    {\n        XYZ,\n        XY,\n        XZ,\n        YZ,\n        X,\n        Y,\n        Z\n    }\n\n    public enum TypeFollowTarget\n    {\n        SetPosition,\n        Lerp,\n        SmoothDamp\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/FollowTargetComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1822db19afe741b39a1a8aaf05bb65fa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/MoveComponent.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.Events;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class MoveComponent : BaseMono\n    {\n        public GameObject movingObject;\n\n        public List<Transform> points; // List of points the object will move through\n        public float speed = 1.0f; // The speed at which the object will move between points\n        public bool moveOnAwake = true; // Flag to indicate whether the object should start moving on awake\n        public bool loop = true; // Flag to indicate whether the object should loop through the points\n        private bool _reverse; // Flag to indicate whether the object should move in reverse\n        private int _currentPoint; // The current point the object is moving towards\n        private bool _isMoving = true; // Flag to indicate whether the object is currently moving\n        public UnityEvent<int> onPointReached; // Unity event to notify when a point is reached\n\n        void Start()\n        {\n            movingObject.transform.position = points[0].position;\n            if (!moveOnAwake)\n            {\n                _isMoving = false;\n            }\n        }\n\n        public override void Tick()\n        {\n            base.Tick();\n            if (_isMoving)\n            {\n                if (_currentPoint < points.Count)\n                {\n                    // Move the object towards the next point\n                    movingObject.transform.position = Vector3.MoveTowards(movingObject.transform.position,\n                        points[_currentPoint].position, speed * Time.deltaTime);\n                    if (movingObject.transform.position == points[_currentPoint].position)\n                    {\n                        // When the object reaches the point, move on to the next one\n                        onPointReached?.Invoke(_currentPoint);\n                        if (!_reverse)\n                        {\n                            _currentPoint++;\n                        }\n                        else\n                        {\n                            _currentPoint--;\n                        }\n\n                        if (_currentPoint == points.Count && loop)\n                        {\n                            _currentPoint = 0;\n                        }\n\n                        if (_currentPoint < 0 && loop)\n                        {\n                            _currentPoint = points.Count - 1;\n                        }\n                    }\n                }\n            }\n        }\n\n        public void StopMoving()\n        {\n            _isMoving = false;\n        }\n\n        public void ResumeMoving()\n        {\n            _isMoving = true;\n        }\n\n        public void ReverseMoving()\n        {\n            _reverse = !_reverse;\n            if (_currentPoint == 0)\n            {\n                _currentPoint = points.Count - 1;\n            }\n            else if (_currentPoint == points.Count - 1)\n            {\n                _currentPoint = 0;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/MoveComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 46e435ee81f643968c015f2e2c597987\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/ResizeCameraOrthographicComponent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class ResizeCameraOrthographicComponent : CacheComponent<Camera>\n    {\n        [SerializeField] private Vector2 ratio = new Vector2(9, 16);\n\n        protected override void Awake()\n        {\n            base.Awake();\n            float sizeStart = component.orthographicSize;\n            float size = component.orthographicSize * ratio.x / (ratio.y * component.aspect);\n            if (size > sizeStart)\n                component.orthographicSize = size;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/ResizeCameraOrthographicComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4d0482e28b214f308276639a11ee7036\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/ResizeMatchCanvasScalerComponent.cs",
    "content": "using UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class ResizeMatchCanvasScalerComponent : CacheComponent<CanvasScaler>\n    {\n        [SerializeField, Range(0, 1)] private float aspectRatio = 0.6f;\n        [SerializeField] private Canvas canvas;\n        [SerializeField, ReadOnly] private Camera camera;\n\n        protected override void Awake()\n        {\n            base.Awake();\n            GetCanvas();\n            if (camera != null)\n            {\n                component.matchWidthOrHeight = camera.aspect > aspectRatio ? 1 : 0;\n            }\n        }\n\n        void GetCanvas()\n        {\n            if (canvas == null)\n            {\n                canvas = GetComponent<Canvas>();\n                if (canvas.worldCamera)\n                {\n                    camera = canvas.worldCamera;\n                }\n            }\n        }\n#if UNITY_EDITOR\n        protected override void Reset()\n        {\n            base.Reset();\n            GetCanvas();\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/ResizeMatchCanvasScalerComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bdbb49ade0bd47989ddd583f82a20a8a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/RotateComponent.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class RotateComponent : BaseMono\n    {\n        [Header(\"Attributes\")] public bool ignoreTimeScale;\n\n        public float speed = 1f;\n        public bool rotateX;\n        public bool rotateY;\n        public bool rotateZ;\n        public bool isReverse;\n        private bool isRotate = true;\n\n        public void Resume()\n        {\n            isRotate = true;\n        }\n\n        public void Pause()\n        {\n            isRotate = false;\n        }\n\n        public override void FixedTick()\n        {\n            base.FixedTick();\n            if (isRotate)\n            {\n                var transformTemp = transform;\n                if (rotateX)\n                {\n                    if (!isReverse)\n                    {\n                        transform.RotateAround(transform.position, transform.right, Time.deltaTime * 90f * speed);\n                    }\n                    else\n                    {\n                        transform.RotateAround(transform.position, transform.right, Time.deltaTime * 90f * -speed);\n                    }\n                }\n\n                if (rotateY)\n                {\n                    if (!isReverse)\n                    {\n                        transform.RotateAround(transform.position, transform.up, Time.deltaTime * 90f * speed);\n                    }\n                    else\n                    {\n                        transform.RotateAround(transform.position, transform.up, Time.deltaTime * 90f * -speed);\n                    }\n                }\n\n                if (rotateZ)\n                {\n                    if (!isReverse)\n                    {\n                        transform.RotateAround(transform.position, transform.forward, Time.deltaTime * 90f * speed * 1);\n                    }\n                    else\n                    {\n                        transform.RotateAround(transform.position, transform.forward,\n                            Time.deltaTime * 90f * speed * -1);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/RotateComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 21b97e3cc6124c14912dd93f240fe259\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SafeAreaComponent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    /// <summary>\n    /// Safe area implementation for notched mobile devices. Usage:\n    ///  (1) Add this component to the top level of any GUI panel. \n    ///  (2) If the panel uses a full screen background image, then create an immediate child and put the component on that instead, with all other elements childed below it.\n    ///      This will allow the background image to stretch to the full extents of the screen behind the notch, which looks nicer.\n    ///  (3) For other cases that use a mixture of full horizontal and vertical background stripes, use the Conform X & Y controls on separate elements as needed.\n    /// </summary>\n    [HideMonoScript]\n    [EditorIcon(\"icon_csharp\")]\n    public class SafeAreaComponent : BaseMono\n    {\n        #region Simulations\n\n        /// <summary>\n        /// Simulation device that uses safe area due to a physical notch or software home bar. For use in Editor only.\n        /// </summary>\n        public enum SimDevice\n        {\n            /// <summary>\n            /// Don't use a simulated safe area - GUI will be full screen as normal.\n            /// </summary>\n            None,\n\n            /// <summary>\n            /// Simulate the iPhone X and Xs (identical safe areas).\n            /// </summary>\n            iPhoneX,\n\n            /// <summary>\n            /// Simulate the iPhone Xs Max and XR (identical safe areas).\n            /// </summary>\n            iPhoneXsMax,\n\n            /// <summary>\n            /// Simulate the Google Pixel 3 XL using landscape left.\n            /// </summary>\n            Pixel3XL_LSL,\n\n            /// <summary>\n            /// Simulate the Google Pixel 3 XL using landscape right.\n            /// </summary>\n            Pixel3XL_LSR\n        }\n\n        /// <summary>\n        /// Simulation mode for use in editor only. This can be edited at runtime to toggle between different safe areas.\n        /// </summary>\n        public static SimDevice Sim = SimDevice.None;\n\n        /// <summary>\n        /// Normalised safe areas for iPhone X with Home indicator (ratios are identical to Xs, 11 Pro). Absolute values:\n        ///  PortraitU x=0, y=102, w=1125, h=2202 on full extents w=1125, h=2436;\n        ///  PortraitD x=0, y=102, w=1125, h=2202 on full extents w=1125, h=2436 (not supported, remains in Portrait Up);\n        ///  LandscapeL x=132, y=63, w=2172, h=1062 on full extents w=2436, h=1125;\n        ///  LandscapeR x=132, y=63, w=2172, h=1062 on full extents w=2436, h=1125.\n        ///  Aspect Ratio: ~19.5:9.\n        /// </summary>\n        Rect[] NSA_iPhoneX = new Rect[]\n        {\n            new Rect(0f, 102f / 2436f, 1f, 2202f / 2436f), // Portrait\n            new Rect(132f / 2436f, 63f / 1125f, 2172f / 2436f, 1062f / 1125f) // Landscape\n        };\n\n        /// <summary>\n        /// Normalised safe areas for iPhone Xs Max with Home indicator (ratios are identical to XR, 11, 11 Pro Max). Absolute values:\n        ///  PortraitU x=0, y=102, w=1242, h=2454 on full extents w=1242, h=2688;\n        ///  PortraitD x=0, y=102, w=1242, h=2454 on full extents w=1242, h=2688 (not supported, remains in Portrait Up);\n        ///  LandscapeL x=132, y=63, w=2424, h=1179 on full extents w=2688, h=1242;\n        ///  LandscapeR x=132, y=63, w=2424, h=1179 on full extents w=2688, h=1242.\n        ///  Aspect Ratio: ~19.5:9.\n        /// </summary>\n        Rect[] NSA_iPhoneXsMax = new Rect[]\n        {\n            new Rect(0f, 102f / 2688f, 1f, 2454f / 2688f), // Portrait\n            new Rect(132f / 2688f, 63f / 1242f, 2424f / 2688f, 1179f / 1242f) // Landscape\n        };\n\n        /// <summary>\n        /// Normalised safe areas for Pixel 3 XL using landscape left. Absolute values:\n        ///  PortraitU x=0, y=0, w=1440, h=2789 on full extents w=1440, h=2960;\n        ///  PortraitD x=0, y=0, w=1440, h=2789 on full extents w=1440, h=2960;\n        ///  LandscapeL x=171, y=0, w=2789, h=1440 on full extents w=2960, h=1440;\n        ///  LandscapeR x=0, y=0, w=2789, h=1440 on full extents w=2960, h=1440.\n        ///  Aspect Ratio: 18.5:9.\n        /// </summary>\n        Rect[] NSA_Pixel3XL_LSL = new Rect[]\n        {\n            new Rect(0f, 0f, 1f, 2789f / 2960f), // Portrait\n            new Rect(0f, 0f, 2789f / 2960f, 1f) // Landscape\n        };\n\n        /// <summary>\n        /// Normalised safe areas for Pixel 3 XL using landscape right. Absolute values and aspect ratio same as above.\n        /// </summary>\n        Rect[] NSA_Pixel3XL_LSR = new Rect[]\n        {\n            new Rect(0f, 0f, 1f, 2789f / 2960f), // Portrait\n            new Rect(171f / 2960f, 0f, 2789f / 2960f, 1f) // Landscape\n        };\n\n        #endregion\n\n        RectTransform Panel;\n        Rect LastSafeArea = new Rect(0, 0, 0, 0);\n        Vector2Int LastScreenSize = new Vector2Int(0, 0);\n        ScreenOrientation LastOrientation = ScreenOrientation.AutoRotation;\n\n        [SerializeField]\n        bool ConformX = true; // Conform to screen safe area on X-axis (default true, disable to ignore)\n\n        [SerializeField]\n        bool ConformY = true; // Conform to screen safe area on Y-axis (default true, disable to ignore)\n\n        [SerializeField]\n        bool Logging = false; // Conform to screen safe area on Y-axis (default true, disable to ignore)\n\n        void Awake()\n        {\n            Panel = GetComponent<RectTransform>();\n\n            if (Panel == null)\n            {\n                Debug.LogError(\"Cannot apply safe area - no RectTransform found on \" + name);\n                Destroy(gameObject);\n            }\n\n            Refresh();\n        }\n\n        public override void Tick()\n        {\n            base.Tick();\n            Refresh();\n        }\n\n        void Refresh()\n        {\n            Rect safeArea = GetSafeArea();\n\n            if (safeArea != LastSafeArea\n                || Screen.width != LastScreenSize.x\n                || Screen.height != LastScreenSize.y\n                || Screen.orientation != LastOrientation)\n            {\n                // Fix for having auto-rotate off and manually forcing a screen orientation.\n                // See https://forum.unity.com/threads/569236/#post-4473253 and https://forum.unity.com/threads/569236/page-2#post-5166467\n                LastScreenSize.x = Screen.width;\n                LastScreenSize.y = Screen.height;\n                LastOrientation = Screen.orientation;\n\n                ApplySafeArea(safeArea);\n            }\n        }\n\n        Rect GetSafeArea()\n        {\n            Rect safeArea = Screen.safeArea;\n\n            if (Application.isEditor && Sim != SimDevice.None)\n            {\n                Rect nsa = new Rect(0, 0, Screen.width, Screen.height);\n\n                switch (Sim)\n                {\n                    case SimDevice.iPhoneX:\n                        if (Screen.height > Screen.width) // Portrait\n                            nsa = NSA_iPhoneX[0];\n                        else // Landscape\n                            nsa = NSA_iPhoneX[1];\n                        break;\n                    case SimDevice.iPhoneXsMax:\n                        if (Screen.height > Screen.width) // Portrait\n                            nsa = NSA_iPhoneXsMax[0];\n                        else // Landscape\n                            nsa = NSA_iPhoneXsMax[1];\n                        break;\n                    case SimDevice.Pixel3XL_LSL:\n                        if (Screen.height > Screen.width) // Portrait\n                            nsa = NSA_Pixel3XL_LSL[0];\n                        else // Landscape\n                            nsa = NSA_Pixel3XL_LSL[1];\n                        break;\n                    case SimDevice.Pixel3XL_LSR:\n                        if (Screen.height > Screen.width) // Portrait\n                            nsa = NSA_Pixel3XL_LSR[0];\n                        else // Landscape\n                            nsa = NSA_Pixel3XL_LSR[1];\n                        break;\n                    default:\n                        break;\n                }\n\n                safeArea = new Rect(Screen.width * nsa.x, Screen.height * nsa.y, Screen.width * nsa.width,\n                    Screen.height * nsa.height);\n            }\n\n            return safeArea;\n        }\n\n        void ApplySafeArea(Rect r)\n        {\n            LastSafeArea = r;\n\n            // Ignore x-axis?\n            if (!ConformX)\n            {\n                r.x = 0;\n                r.width = Screen.width;\n            }\n\n            // Ignore y-axis?\n            if (!ConformY)\n            {\n                r.y = 0;\n                r.height = Screen.height;\n            }\n\n            // Check for invalid screen startup state on some Samsung devices (see below)\n            if (Screen.width > 0 && Screen.height > 0)\n            {\n                // Convert safe area rectangle from absolute pixels to normalised anchor coordinates\n                Vector2 anchorMin = r.position;\n                Vector2 anchorMax = r.position + r.size;\n                anchorMin.x /= Screen.width;\n                anchorMin.y /= Screen.height;\n                anchorMax.x /= Screen.width;\n                anchorMax.y /= Screen.height;\n\n                // Fix for some Samsung devices (e.g. Note 10+, A71, S20) where Refresh gets called twice and the first time returns NaN anchor coordinates\n                // See https://forum.unity.com/threads/569236/page-2#post-6199352\n                if (anchorMin.x >= 0 && anchorMin.y >= 0 && anchorMax.x >= 0 && anchorMax.y >= 0)\n                {\n                    Panel.anchorMin = anchorMin;\n                    Panel.anchorMax = anchorMax;\n                }\n            }\n\n            if (Logging)\n            {\n                Debug.LogFormat(\"New safe area applied to {0}: x={1}, y={2}, w={3}, h={4} on full extents w={5}, h={6}\",\n                    name, r.x, r.y, r.width, r.height, Screen.width, Screen.height);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/SafeAreaComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 09edf4ad864147a9bd2de10bb1a5c654\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeleton.cs",
    "content": "#if VIRTUESKY_SKELETON\nusing System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing Spine;\nusing Spine.Unity;\nusing AnimationState = Spine.AnimationState;\n\nnamespace VirtueSky.Component\n{\n    public abstract class AnimationSkeleton : MonoBehaviour\n    {\n        protected Skeleton skeleton;\n        protected AnimationState animationState;\n        protected string animationName;\n        public Skeleton Skeleton => skeleton;\n        public AnimationState AnimationState => animationState;\n        public string AnimationName => animationName;\n        protected Dictionary<string, Action> cacheEvent = new Dictionary<string, Action>();\n\n        public virtual void Init()\n        {\n            animationState.Event += HandleAnimationStateEvent;\n        }\n\n        public abstract void Initialize(bool reload = false);\n        public abstract void ChangeAnimationName(string animationName);\n        public abstract void FlipX(bool isFlipX = false);\n        public abstract void FlipY(bool isFlipY = false);\n        public abstract void ChangeDataAsset(SkeletonDataAsset dataAsset);\n\n        public void AddAnimation(int trackIndex, string animationName, bool loop, float timeDelay = 0)\n        {\n            animationState.AddAnimation(trackIndex, animationName, loop, timeDelay);\n        }\n\n        public TrackEntry PlayAnimation(int trackIndex, string animationName, bool loop = false,\n            float speed = 1)\n        {\n            this.animationName = animationName;\n            animationState.TimeScale = speed;\n            var trackEntry = animationState.SetAnimation(trackIndex, animationName, loop);\n            animationState.Apply(skeleton);\n            return trackEntry;\n        }\n\n        public void RegisterEvent(string eventName, Action actionEvent = null)\n        {\n            if (cacheEvent.ContainsKey(eventName))\n            {\n                cacheEvent[eventName] = actionEvent;\n            }\n            else\n            {\n                cacheEvent.Add(eventName, actionEvent);\n            }\n        }\n\n        public void StopAnimation()\n        {\n            animationState.TimeScale = 0;\n        }\n\n        protected void HandleAnimationStateEvent(TrackEntry trackEntry, Spine.Event e)\n        {\n            Action action = null;\n            if (cacheEvent.TryGetValue(e.Data.Name, out action))\n            {\n                action?.Invoke();\n            }\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeleton.cs.meta",
    "content": "fileFormatVersion: 2\nguid: adb2ca79f8f64dceaa0f39d965cf5d6d\ntimeCreated: 1708057049"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonComponent.cs",
    "content": "#if VIRTUESKY_SKELETON\nusing Spine.Unity;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(SkeletonAnimation))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class AnimationSkeletonComponent : AnimationSkeleton\n    {\n        [SerializeField] SkeletonAnimation skeletonAnimation;\n        public SkeletonAnimation SkeletonAnimation => skeletonAnimation;\n\n        public override void Init()\n        {\n            skeleton = skeletonAnimation.Skeleton;\n            animationState = skeletonAnimation.AnimationState;\n            base.Init();\n        }\n\n        public override void Initialize(bool reload = false)\n        {\n            skeletonAnimation.Initialize(reload);\n        }\n\n        public override void ChangeAnimationName(string animationName)\n        {\n            skeletonAnimation.AnimationName = animationName;\n        }\n\n        public override void FlipX(bool isFlipX = false)\n        {\n            skeletonAnimation.initialFlipX = isFlipX;\n        }\n\n        public override void FlipY(bool isFlipY = false)\n        {\n            skeletonAnimation.initialFlipY = isFlipY;\n        }\n\n        public override void ChangeDataAsset(SkeletonDataAsset dataAsset)\n        {\n            skeletonAnimation.skeletonDataAsset = dataAsset;\n        }\n\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            if (skeletonAnimation == null)\n            {\n                skeletonAnimation = GetComponent<SkeletonAnimation>();\n            }\n        }\n#endif\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 72d87d7da8ad434aba0a028f7a110682\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonUIComponent.cs",
    "content": "#if VIRTUESKY_SKELETON\nusing Spine.Unity;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(SkeletonGraphic))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class AnimationSkeletonUIComponent : AnimationSkeleton\n    {\n        [SerializeField] SkeletonGraphic skeletonGraphic;\n        public SkeletonGraphic SkeletonGraphic => skeletonGraphic;\n\n        public override void Init()\n        {\n            skeleton = skeletonGraphic.Skeleton;\n            animationState = skeletonGraphic.AnimationState;\n            base.Init();\n        }\n\n        public override void Initialize(bool reload = false)\n        {\n            skeletonGraphic.Initialize(reload);\n        }\n\n        public override void ChangeAnimationName(string animationName)\n        {\n            skeletonGraphic.startingAnimation = animationName;\n        }\n\n        public override void FlipX(bool isFlipX = false)\n        {\n            skeletonGraphic.initialFlipX = isFlipX;\n        }\n\n        public override void FlipY(bool isFlipY = false)\n        {\n            skeletonGraphic.initialFlipY = isFlipY;\n        }\n\n        public override void ChangeDataAsset(SkeletonDataAsset dataAsset)\n        {\n            skeletonGraphic.skeletonDataAsset = dataAsset;\n        }\n\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            if (skeletonGraphic == null)\n            {\n                skeletonGraphic = GetComponent<SkeletonGraphic>();\n            }\n        }\n#endif\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton/AnimationSkeletonUIComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9b460082b10946a1b933bf18b723251d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/AnimationSkeleton.meta",
    "content": "fileFormatVersion: 2\nguid: e11352e7a4fed8a47986e9dd820ea474\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeleton.cs",
    "content": "#if VIRTUESKY_SKELETON\nusing System.Collections.Generic;\nusing Spine;\nusing UnityEngine;\nusing AnimationState = Spine.AnimationState;\n\nnamespace VirtueSky.Component\n{\n    public abstract class SkinSkeleton : MonoBehaviour\n    {\n        protected Skeleton skeleton;\n        protected Spine.AnimationState animationState;\n        public Skeleton Skeleton => skeleton;\n        public AnimationState AnimationState => animationState;\n\n        public abstract void Init();\n\n        public virtual void MixSkin(string mixSkinName)\n        {\n            if (skeleton == null) return;\n            if (string.IsNullOrEmpty(mixSkinName) || mixSkinName.Equals(\"default\")) return;\n            skeleton.Skin.AddSkin(skeleton.Data.FindSkin(mixSkinName));\n            skeleton.SetSlotsToSetupPose();\n            animationState.Apply(skeleton);\n        }\n\n        public virtual void MixSkin(List<string> listMixSkinName)\n        {\n            if (skeleton == null) return;\n            foreach (var skinMixName in listMixSkinName)\n            {\n                if (!string.IsNullOrEmpty(skinMixName) && !skinMixName.Equals(\"default\"))\n                {\n                    skeleton.Skin.AddSkin(skeleton.Data.FindSkin(skinMixName));\n                }\n            }\n\n            skeleton.SetSlotsToSetupPose();\n            animationState.Apply(skeleton);\n        }\n\n        public virtual void MixNewSkin(string mixSkinName)\n        {\n            if (skeleton == null) return;\n            if (string.IsNullOrEmpty(mixSkinName) || mixSkinName.Equals(\"default\")) return;\n            var mixAndMatchSkin = new Skin(\"temp\");\n            mixAndMatchSkin.AddSkin(skeleton.Data.FindSkin(mixSkinName));\n            skeleton.SetSkin(mixAndMatchSkin);\n            skeleton.SetSlotsToSetupPose();\n            animationState.Apply(skeleton);\n        }\n\n        public virtual void MixNewSkin(List<string> listMixSkinName)\n        {\n            if (skeleton == null) return;\n            var mixAndMatchSkin = new Skin(\"temp\");\n            foreach (var skinMixName in listMixSkinName)\n            {\n                if (!string.IsNullOrEmpty(skinMixName) && !skinMixName.Equals(\"default\"))\n                {\n                    mixAndMatchSkin.AddSkin(skeleton.Data.FindSkin(skinMixName));\n                }\n            }\n\n            skeleton.SetSkin(mixAndMatchSkin);\n            skeleton.SetSlotsToSetupPose();\n            animationState.Apply(skeleton);\n        }\n\n        public virtual void SetSkin(string skinName)\n        {\n            if (skeleton == null) return;\n            Skin newSkin = new Skin(\"skin\");\n            newSkin.AddSkin(skeleton.Data.FindSkin(skinName));\n            skeleton.SetSkin(newSkin);\n            skeleton.SetSlotsToSetupPose();\n            animationState.Apply(skeleton);\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeleton.cs.meta",
    "content": "fileFormatVersion: 2\nguid: df6ec86372015434fbefc86e083ad0a3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonComponent.cs",
    "content": "#if VIRTUESKY_SKELETON\nusing Spine.Unity;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(SkeletonAnimation))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class SkinSkeletonComponent : SkinSkeleton\n    {\n        [SerializeField] private SkeletonAnimation skeletonAnimation;\n        public SkeletonAnimation SkeletonAnimation => skeletonAnimation;\n\n        public override void Init()\n        {\n            skeleton = skeletonAnimation.Skeleton;\n            animationState = skeletonAnimation.AnimationState;\n        }\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            if (skeletonAnimation == null)\n            {\n                skeletonAnimation = GetComponent<SkeletonAnimation>();\n            }\n        }\n#endif\n    }\n}\n\n#endif"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7cc89fd779894fa4abbd3a16effefe80\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonUIComponent.cs",
    "content": "#if VIRTUESKY_SKELETON\nusing System;\nusing Spine.Unity;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [RequireComponent(typeof(SkeletonGraphic))]\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class SkinSkeletonUIComponent : SkinSkeleton\n    {\n        [SerializeField] private SkeletonGraphic skeletonGraphic;\n\n        public override void Init()\n        {\n            skeleton = skeletonGraphic.Skeleton;\n            animationState = skeletonGraphic.AnimationState;\n        }\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            if (skeletonGraphic == null)\n            {\n                skeletonGraphic = GetComponent<SkeletonGraphic>();\n            }\n        }\n#endif\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton/SkinSkeletonUIComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 98a5b0f9dbf84aec9ebc52442d5bbe16\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent/SkinSkeleton.meta",
    "content": "fileFormatVersion: 2\nguid: 998923b56f42400469041e4440a898bf\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/SkeletonComponent.meta",
    "content": "fileFormatVersion: 2\nguid: 9f90ca78d90fcd84fa3aec9942675b57\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/TimeRemainingComponent.cs",
    "content": "﻿using System;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Component\n{\n    [EditorIcon(\"icon_csharp\"), HideMonoScript]\n    public class TimeRemainingComponent : BaseMono\n    {\n        [SerializeField] private int targetYear;\n\n        [SerializeField] private int targetMonth;\n\n        [SerializeField] private int targetDay;\n\n        [SerializeField] private int targetHour;\n\n        [SerializeField] private int targetMinute;\n\n        [SerializeField] private int targetSecond;\n\n        private DateTime targetTime;\n\n\n        public void InitTargetTime()\n        {\n            targetTime = new DateTime(targetYear, targetMonth, targetDay, targetHour, targetMinute, targetSecond);\n        }\n\n        public void InitTargetTime(int year, int month, int day, int hour, int minute, int second)\n        {\n            targetTime = new DateTime(year, month, day, hour, minute, second);\n        }\n\n        public TimeSpan GetTimeRemaining()\n        {\n            return (targetTime - DateTime.Now).TotalSeconds > 0 ? (targetTime - DateTime.Now) : TimeSpan.Zero;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Component/TimeRemainingComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: afeabd83b21c46eaa3666eb81ba90e20\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component/virtuesky.sunflower.component.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Component\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:80ecb87cae9c44d19824e70ea7229748\",\n        \"GUID:72d1fea872bd7a449bf3818f2b0a6708\",\n        \"GUID:68765d262e2128e4ab49c983f3411946\",\n        \"GUID:f51ebe6a0ceec4240a699833d6309b23\",\n        \"GUID:4c25c05f410a3a447a75c3b0909152ef\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Component/virtuesky.sunflower.component.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 9fb70e528497d88469e13fc11e3eb30e\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Component.meta",
    "content": "fileFormatVersion: 2\nguid: e48d2f41f2ea4bc3ab451313aeb9b63c\ntimeCreated: 1697785718"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAboutDrawer.cs",
    "content": "﻿using System;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPAboutDrawer\n    {\n        public static void OnDrawAbout(Rect position, Action drawSetting = null)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            GUILayout.BeginHorizontal();\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.About, \"About\");\n            GUILayout.Space(10);\n            GUILayout.TextArea(\"Name: Sunflower\", EditorStyles.boldLabel);\n            GUILayout.TextArea(\n                \"Description: Core ScriptableObject architecture for building Unity games\",\n                EditorStyles.boldLabel);\n            GUILayout.TextArea($\"Version: {ConstantPackage.VersionSunflower}\",\n                EditorStyles.boldLabel);\n            GUILayout.TextArea(\"Author: VirtueSky\", EditorStyles.boldLabel);\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Open GitHub Repository\"))\n            {\n                Application.OpenURL(\"https://github.com/VirtueSky/sunflower\");\n            }\n\n            if (GUILayout.Button(\"Document\"))\n            {\n                Application.OpenURL(\"https://github.com/VirtueSky/sunflower/wiki\");\n            }\n\n            GUILayout.Space(10);\n\n            GUILayout.EndVertical();\n            GUILayout.Box(EditorResources.IconVirtueSky, GUIStyle.none,\n                GUILayout.Width(180), GUILayout.Height(180));\n            GUILayout.EndHorizontal();\n\n\n            GUILayout.Space(10);\n            CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAboutDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cfde9ce3b42341abbdc803fd81396955\ntimeCreated: 1704944352"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAdjustDrawer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Tracking;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPAdjustDrawer\n    {\n        private static VirtueSky.Tracking.AdjustConfig _config;\n        private static UnityEditor.Editor _editor;\n\n        public static void OnEnable()\n        {\n            Init();\n        }\n\n        private static void Init()\n        {\n            if (_editor != null) _editor = null;\n            _config = CreateAsset.GetScriptableAsset<VirtueSky.Tracking.AdjustConfig>();\n            _editor = UnityEditor.Editor.CreateEditor(_config);\n        }\n\n\n        public static void OnDrawAdjust()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.Adjust, \"Adjust\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonInstallPackage(\"Install Adjust\", \"Remove Adjust\",\n                ConstantPackage.PackageNameAdjust, ConstantPackage.MaxVersionAdjust);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Add define symbols\");\n            GUILayout.Space(10);\n#if !VIRTUESKY_ADJUST\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_ADJUST} for Adjust to use\",\n                MessageType.Info);\n#endif\n            GUILayout.Space(10);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADJUST);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            CPUtility.DrawHeader(\"Adjust Config\");\n            GUILayout.Space(10);\n            if (_config == null)\n            {\n                if (GUILayout.Button(\"Create AdjustConfig\"))\n                {\n                    _config =\n                        CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Tracking.AdjustConfig>(\"/AdjustTracking/Resources\",\n                            isPingAsset: false);\n                    Init();\n                }\n            }\n            else\n            {\n                if (_editor == null)\n                {\n                    EditorGUILayout.HelpBox(\"Couldn't create the settings editor.\",\n                        MessageType.Error);\n                    return;\n                }\n                else\n                {\n                    _editor.OnInspectorGUI();\n                }\n            }\n\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Adjust Tracking\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Create Scriptable Tracking Adjust\"))\n            {\n                TrackingWindowEditor.CreateTrackingAdjust();\n            }\n\n            GUILayout.Space(10);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Ping AdjustConfig\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Ping\"))\n            {\n                if (_config == null)\n                {\n                    Debug.LogError(\"AdjustConfig have not been created yet\");\n                }\n                else\n                {\n                    EditorGUIUtility.PingObject(_config);\n                    Selection.activeObject = _config;\n                }\n            }\n\n            GUILayout.Space(10);\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAdjustDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b93284e9903c4672ae0688d4a5b5294b\ntimeCreated: 1717511923"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAdvertisingDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Ads;\nusing VirtueSky.Inspector;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPAdvertisingDrawer\n    {\n        private static Vector2 _scrollPosition;\n        private static UnityEditor.Editor _editor;\n        private static AdSetting _adSetting;\n        private static Vector2 scroll = Vector2.zero;\n\n        public static void OnEnable()\n        {\n            Init();\n        }\n\n        public static void Init()\n        {\n            if (_editor != null)\n            {\n                _editor = null;\n            }\n\n            _adSetting = CreateAsset.GetScriptableAsset<AdSetting>();\n            _editor = UnityEditor.Editor.CreateEditor(_adSetting);\n        }\n\n        public static void OnDrawAdvertising()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.Advertising, \"Advertising\");\n            GUILayout.Space(10);\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n            if (_adSetting == null)\n            {\n                if (GUILayout.Button(\"Create AdSetting\"))\n                {\n                    _adSetting =\n                        CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Ads.AdSetting>(\"/Ads/Setting\",\n                            isPingAsset: false);\n                    Init();\n                }\n            }\n            else\n            {\n                if (_editor == null)\n                {\n                    EditorGUILayout.HelpBox(\"Couldn't create the settings resources editor.\",\n                        MessageType.Error);\n                    return;\n                }\n                else\n                {\n                    _editor.OnInspectorGUI();\n                }\n\n                DrawDefineSymbols();\n                DrawInstallSdk();\n            }\n\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Ping Ads Settings\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Ping\"))\n            {\n                if (_adSetting == null)\n                {\n                    Debug.LogError(\"AdSetting have not been created yet\");\n                }\n                else\n                {\n                    EditorGUIUtility.PingObject(_adSetting);\n                    Selection.activeObject = _adSetting;\n                }\n            }\n\n            GUILayout.Space(10);\n            EditorGUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n\n        static void DrawDefineSymbols()\n        {\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define Symbols\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADS);\n            if (_adSetting.UseAppLovin)\n            {\n#if !VIRTUESKY_ADS || !VIRTUESKY_APPLOVIN\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols \\\"{ConstantDefineSymbols.VIRTUESKY_ADS}\\\" and \\\"{ConstantDefineSymbols.VIRTUESKY_APPLOVIN}\\\" to use Max Ads\",\n                MessageType.Info);\n#endif\n                CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLOVIN);\n            }\n\n            if (_adSetting.UseAdmob)\n            {\n#if !VIRTUESKY_ADS || !VIRTUESKY_ADMOB\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols \\\"{ConstantDefineSymbols.VIRTUESKY_ADS}\\\" and \\\"{ConstantDefineSymbols.VIRTUESKY_ADMOB}\\\" to use Admob Ads\",\n                MessageType.Info);\n#endif\n                CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADMOB);\n            }\n\n            if (_adSetting.UseLevelPlay)\n            {\n#if !VIRTUESKY_ADS || !VIRTUESKY_LEVELPLAY\n                EditorGUILayout.HelpBox(\n                    $\"Add scripting define symbols \\\"{ConstantDefineSymbols.VIRTUESKY_ADS}\\\" and \\\"{ConstantDefineSymbols.VIRTUESKY_LEVELPLAY}\\\" to use IronSource Ads\",\n                    MessageType.Info);\n#endif\n\n                CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_LEVELPLAY);\n            }\n        }\n\n        static void DrawInstallSdk()\n        {\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Install Sdk\");\n            GUILayout.Space(10);\n            if (_adSetting.UseAppLovin)\n            {\n                GUILayout.Space(10);\n                if (GUILayout.Button(\"Install Max Sdk Plugin\"))\n                {\n                    AssetDatabase.ImportPackage(\n                        FileExtension.GetPathFileInCurrentEnvironment(\n                            \"VirtueSky/Utils/Editor/UnityPackage/max-sdk.unitypackage\"), false);\n                }\n            }\n\n            if (_adSetting.UseAdmob)\n            {\n                GUILayout.Space(10);\n                CPUtility.DrawButtonInstallPackage(\"Install Admob Sdk Plugin\", \"Remove Admob Sdk Plugin\",\n                    ConstantPackage.PackageNameAdmob, ConstantPackage.VersionAdmob);\n            }\n\n            if (_adSetting.UseLevelPlay)\n            {\n                GUILayout.Space(10);\n                CPUtility.DrawButtonInstallPackage(\"Install LevelPlay Sdk Plugin\", \"Remove LevelPlay Sdk Plugin\",\n                    ConstantPackage.PackageNameLevelPlay, ConstantPackage.MaxVersionLevelPlay);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAdvertisingDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 99b17fe6aaad476ca0806f0d593479b1\ntimeCreated: 1704942542"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAppsFlyerDrawer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Tracking;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPAppsFlyerDrawer\n    {\n        private static VirtueSky.Tracking.AppsFlyerConfig _config;\n        private static UnityEditor.Editor _editor;\n        private static Vector2 scroll = Vector2.zero;\n\n        public static void OnEnable()\n        {\n            Init();\n        }\n\n        private static void Init()\n        {\n            if (_editor != null) _editor = null;\n            _config = CreateAsset.GetScriptableAsset<VirtueSky.Tracking.AppsFlyerConfig>();\n            _editor = UnityEditor.Editor.CreateEditor(_config);\n        }\n\n        public static void OnDrawAppsFlyer()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.AppsFlyer, \"AppsFlyer\");\n            GUILayout.Space(10);\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n            CPUtility.DrawButtonInstallPackage(\"Install AppsFlyer\", \"Remove AppsFlyer\",\n                ConstantPackage.PackageNameAppFlyer, ConstantPackage.MaxVersionAppFlyer);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n#if !VIRTUESKY_APPSFLYER\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_APPSFLYER} for AppsFlyer to use\",\n                MessageType.Info);\n#endif\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define Symbols\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPSFLYER);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            CPUtility.DrawHeader(\"AppsFlyer Config\");\n            GUILayout.Space(10);\n            if (_config == null)\n            {\n                if (GUILayout.Button(\"Create AppsFlyerConfig\"))\n                {\n                    _config =\n                        CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Tracking.AppsFlyerConfig>(\n                            \"/AppsFlyerTracking/Resources\",\n                            isPingAsset: false);\n                    Init();\n                }\n            }\n            else\n            {\n                if (_editor == null)\n                {\n                    EditorGUILayout.HelpBox(\"Couldn't create the settings editor.\",\n                        MessageType.Error);\n                    return;\n                }\n                else\n                {\n                    EditorGUILayout.HelpBox(\n                        \"Set your devKey and appID to init the AppsFlyer SDK and start tracking. You must modify these fields and provide:\\ndevKey - Your application devKey provided by AppsFlyer.\\nappId - For iOS only. Your iTunes Application ID.\\nUWP app id - For UWP only. Your application app id \\nMac OS app id - For MacOS app only.\",\n                        MessageType.Info);\n                    _editor.OnInspectorGUI();\n                }\n            }\n\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            CPUtility.DrawHeader(\"AppsFlyer Tracking\");\n            GUILayout.Space(10);\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer No Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAfNoParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer 1 Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAf1Param();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer 2 Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAf2Param();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer 3 Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAf3Param();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer 4 Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAf4Param();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer 5 Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAf5Param();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking AppsFlyer Has Param\"))\n            {\n                TrackingWindowEditor.CreateTrackingAfHasParam();\n            }\n\n            GUILayout.Space(10);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Ping AppsflyerConfig\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Ping\"))\n            {\n                if (_config == null)\n                {\n                    Debug.LogError(\"AppsflyerConfig have not been created yet\");\n                }\n                else\n                {\n                    EditorGUIUtility.PingObject(_config);\n                    Selection.activeObject = _config;\n                }\n            }\n\n            GUILayout.Space(10);\n            EditorGUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAppsFlyerDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cd27eebd6e2b4e7eafee9a99847442ba\ntimeCreated: 1717512747"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAssetFinderDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.AssetFinder.Editor;\nusing VirtueSky.UtilsEditor;\n\n//using VirtueSky.AssetFinder.Editor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPAssetFinderDrawer\n    {\n        public static void OnDrawAssetUsageDetector()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.AssetsFinder, \"Asset Finder\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Open Asset Finder Window (Ctrl+Shift+K / Command+Shift+K)\"))\n            {\n                AssetFinderWindowExtension.ShowWindow();\n            }\n\n            if (GUILayout.Button(\"Delete Finder Cache\"))\n            {\n                AssetFinderWindowExtension.DeleteCache();\n            }\n            GUILayout.Space(10);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.ASSET_FINDER_ADDRESSABLE);\n\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAssetFinderDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 70672f20e14648029029064a97d8aaec\ntimeCreated: 1704943341"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAudioDrawer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Audio;\nusing VirtueSky.AudioEditor;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPAudioDrawer\n    {\n        #region Constants\n        private static class LayoutConstants\n        {\n            public const float PANEL_SPACING = 20f;\n            public const float LEFT_PANEL_MARGIN = 15f;\n            public const float RIGHT_PANEL_MARGIN = 30f;\n            public const float BUTTON_HEIGHT = 25f;\n            public const float HEADER_SPACING = 10f;\n            public const float LINE_THICKNESS = 3f;\n            public const float PING_BUTTON_WIDTH = 100f;\n            public const float QUICK_ACTION_BUTTON_WIDTH = 80f;\n            public const int TEXTURE_SIZE = 2;\n        }\n        \n        private static readonly Color SELECTED_BUTTON_COLOR = new Color(0.3f, 0.5f, 0.85f, 1f);\n        #endregion\n\n        #region Fields\n        public enum AudioTab { Explore, Settings }\n        \n        private static AudioTab audioTab = AudioTab.Explore;\n        private static SoundData selectedSoundData;\n        private static UnityEditor.Editor soundDataEditor;\n        private static EditorWindow hostWindow;\n        \n        private static Vector2 leftPanelScrollPosition = Vector2.zero;\n        private static Vector2 rightPanelScrollPosition = Vector2.zero;\n        \n        private static Texture2D selectedButtonTexture;\n        private static Texture2D normalButtonTexture;\n        private static GUIStyle normalButtonStyle;\n        private static GUIStyle selectedButtonStyle;\n        \n        private static List<SoundData> cachedSoundDataAssets;\n        private static bool needsRefresh = true;\n        private static string searchFilter = \"\";\n        \n        private static SoundData renamingSoundData;\n        private static string renamingText = \"\";\n        private static bool isRenaming = false;\n        #endregion\n\n        #region Initialization & Cleanup\n        [UnityEditor.InitializeOnLoadMethod]\n        private static void Initialize()\n        {\n            EditorApplication.quitting += Cleanup;\n        }\n        \n        [UnityEditor.Callbacks.DidReloadScripts]\n        private static void OnScriptsReloaded()\n        {\n            needsRefresh = true;\n        }\n\n        private static void Cleanup()\n        {\n            DestroyTexture(ref selectedButtonTexture);\n            DestroyTexture(ref normalButtonTexture);\n            DestroyEditor(ref soundDataEditor);\n            \n            cachedSoundDataAssets?.Clear();\n            cachedSoundDataAssets = null;\n            \n            normalButtonStyle = null;\n            selectedButtonStyle = null;\n        }\n\n        private static void DestroyTexture(ref Texture2D texture)\n        {\n            if (texture != null)\n            {\n                Object.DestroyImmediate(texture);\n                texture = null;\n            }\n        }\n\n        private static void DestroyEditor(ref UnityEditor.Editor editor)\n        {\n            if (editor != null)\n            {\n                Object.DestroyImmediate(editor);\n                editor = null;\n            }\n        }\n        #endregion\n\n        #region Asset Management\n        private static List<SoundData> GetSoundDataAssets()\n        {\n            if (cachedSoundDataAssets == null || needsRefresh)\n            {\n                RefreshSoundDataAssets();\n            }\n            return cachedSoundDataAssets;\n        }\n\n        private static void RefreshSoundDataAssets()\n        {\n            var soundDataGuids = AssetDatabase.FindAssets(\"t:SoundData\");\n            cachedSoundDataAssets = new List<SoundData>(soundDataGuids.Length);\n            \n            foreach (var guid in soundDataGuids)\n            {\n                string assetPath = AssetDatabase.GUIDToAssetPath(guid);\n                var soundData = AssetDatabase.LoadAssetAtPath<SoundData>(assetPath);\n                if (soundData != null)\n                {\n                    cachedSoundDataAssets.Add(soundData);\n                }\n            }\n            \n            cachedSoundDataAssets.Sort((a, b) => \n                string.Compare(a.name, b.name, System.StringComparison.Ordinal));\n            \n            needsRefresh = false;\n        }\n\n        private static List<SoundData> GetFilteredSoundDataAssets()\n        {\n            var allAssets = GetSoundDataAssets();\n            \n            if (string.IsNullOrWhiteSpace(searchFilter))\n                return allAssets;\n            \n            return allAssets.FindAll(sd => \n                sd.name.IndexOf(searchFilter, System.StringComparison.OrdinalIgnoreCase) >= 0);\n        }\n        #endregion\n\n        #region Style Management\n        private static void InitializeStyles()\n        {\n            if (normalButtonStyle == null)\n            {\n                normalButtonStyle = new GUIStyle(GUI.skin.button);\n            }\n            \n            if (selectedButtonStyle == null)\n            {\n                selectedButtonStyle = new GUIStyle(GUI.skin.button);\n                \n                if (selectedButtonTexture == null)\n                {\n                    selectedButtonTexture = MakeBackgroundTexture(\n                        LayoutConstants.TEXTURE_SIZE, \n                        SELECTED_BUTTON_COLOR);\n                }\n                \n                selectedButtonStyle.normal.background = selectedButtonTexture;\n                selectedButtonStyle.onNormal.background = selectedButtonTexture;\n                selectedButtonStyle.normal.textColor = Color.white;\n                selectedButtonStyle.hover.background = selectedButtonTexture;\n            }\n        }\n\n        private static Texture2D MakeBackgroundTexture(int size, Color color)\n        {\n            int pixelCount = size * size;\n            Color[] pixels = new Color[pixelCount];\n            for (int i = 0; i < pixelCount; i++)\n            {\n                pixels[i] = color;\n            }\n\n            Texture2D texture = new Texture2D(size, size);\n            texture.SetPixels(pixels);\n            texture.Apply();\n            return texture;\n        }\n        #endregion\n\n        #region Main Drawing\n        public static void OnDrawAudio(Rect position, EditorWindow ownerWindow)\n        {\n            hostWindow = ownerWindow;\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            GUILayout.BeginVertical();\n            \n            CPUtility.DrawHeaderIcon(StatePanelControl.Audio, \"Audio\");\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            \n            DrawTab();\n            \n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            \n            switch (audioTab)\n            {\n                case AudioTab.Explore:\n                    DrawExplore(position);\n                    break;\n                case AudioTab.Settings:\n                    DrawSetting(position);\n                    break;\n            }\n\n            GUILayout.EndVertical();\n        }\n\n        private static void DrawTab()\n        {\n            EditorGUILayout.BeginHorizontal();\n            \n            if (GUILayout.Toggle(audioTab == AudioTab.Explore, \"Explore\",\n                GUI.skin.button, GUILayout.ExpandWidth(true), \n                GUILayout.Height(LayoutConstants.BUTTON_HEIGHT)))\n            {\n                audioTab = AudioTab.Explore;\n            }\n\n            if (GUILayout.Toggle(audioTab == AudioTab.Settings, \"Setting\",\n                GUI.skin.button, GUILayout.ExpandWidth(true), \n                GUILayout.Height(LayoutConstants.BUTTON_HEIGHT)))\n            {\n                audioTab = AudioTab.Settings;\n            }\n\n            EditorGUILayout.EndHorizontal();\n        }\n        #endregion\n\n        #region Explore Tab\n        private static void DrawExplore(Rect position)\n        {\n            CPUtility.DrawLineLastRectX(\n                LayoutConstants.LINE_THICKNESS, \n                GUILayoutUtility.GetLastRect().y, \n                position.width,\n                (position.width - ConstantControlPanel.POSITION_X_START_CONTENT) / 2 - 5);\n            \n            float leftPanelWidth = (position.width - ConstantControlPanel.POSITION_X_START_CONTENT) / 2 \n                - LayoutConstants.LEFT_PANEL_MARGIN;\n            float rightPanelWidth = position.width - ConstantControlPanel.POSITION_X_START_CONTENT \n                - leftPanelWidth - LayoutConstants.RIGHT_PANEL_MARGIN;\n            \n            GUILayout.BeginHorizontal();\n            \n            GUILayout.BeginVertical(GUILayout.Width(leftPanelWidth));\n            DrawLeftExplore();\n            GUILayout.EndVertical();\n            \n            GUILayout.Space(LayoutConstants.PANEL_SPACING);\n            \n            GUILayout.BeginVertical(GUILayout.Width(rightPanelWidth));\n            DrawRightExplore();\n            GUILayout.EndVertical();\n            \n            GUILayout.EndHorizontal();\n        }\n\n        private static void DrawLeftExplore()\n        {\n            DrawSearchBar();\n            GUILayout.Space(5);\n            DrawQuickActions();\n            GUILayout.Space(5);\n            \n            // Handle keyboard input before scrollview to capture events\n            HandleKeyboardInput();\n            \n            leftPanelScrollPosition = GUILayout.BeginScrollView(\n                leftPanelScrollPosition, \n                GUILayout.ExpandHeight(true));\n\n            InitializeStyles();\n            var filteredAssets = GetFilteredSoundDataAssets();\n            \n            foreach (var soundData in filteredAssets)\n            {\n                if (soundData != null)\n                {\n                    DrawSoundDataButton(soundData);\n                }\n            }\n\n            GUILayout.EndScrollView();\n        }\n\n        private static void DrawSearchBar()\n        {\n            GUILayout.BeginHorizontal();\n            GUILayout.Label(\"Search:\", GUILayout.Width(60));\n            \n            EditorGUI.BeginChangeCheck();\n            var searchFieldStyle = GUI.skin.FindStyle(\"ToolbarSearchTextField\") ?? GUI.skin.textField;\n            searchFilter = GUILayout.TextField(searchFilter, searchFieldStyle);\n            \n            if (EditorGUI.EndChangeCheck())\n            {\n                var filtered = GetFilteredSoundDataAssets();\n                if (filtered.Count > 0 && !filtered.Contains(selectedSoundData))\n                {\n                    SelectSoundData(filtered[0]);\n                }\n            }\n            \n            if (GUILayout.Button(\"×\", GUILayout.Width(20)))\n            {\n                searchFilter = \"\";\n                GUI.FocusControl(null);\n            }\n            \n            GUILayout.EndHorizontal();\n        }\n\n        private static void DrawQuickActions()\n        {\n            GUILayout.BeginHorizontal();\n            \n            if (GUILayout.Button(\"Refresh\", \n                GUILayout.Width(LayoutConstants.QUICK_ACTION_BUTTON_WIDTH)))\n            {\n                RefreshSoundDataAssets();\n            }\n            \n            if (GUILayout.Button(\"Create New\", \n                GUILayout.Width(LayoutConstants.QUICK_ACTION_BUTTON_WIDTH)))\n            {\n                AudioWindowEditor.CreateSoundData();\n                needsRefresh = true;\n            }\n            \n            GUILayout.FlexibleSpace();\n            \n            var filteredCount = GetFilteredSoundDataAssets().Count;\n            var totalCount = GetSoundDataAssets().Count;\n            string countText = filteredCount == totalCount \n                ? $\"Total: {totalCount}\" \n                : $\"Showing: {filteredCount}/{totalCount}\";\n            GUILayout.Label(countText, EditorStyles.miniLabel);\n            \n            GUILayout.EndHorizontal();\n        }\n\n        private static void DrawSoundDataButton(SoundData soundData)\n        {\n            if (isRenaming && renamingSoundData == soundData)\n            {\n                DrawRenamingField(soundData);\n            }\n            else\n            {\n                DrawNormalButton(soundData);\n            }\n        }\n\n        private static void DrawNormalButton(SoundData soundData)\n        {\n            var style = (selectedSoundData == soundData) \n                ? selectedButtonStyle \n                : normalButtonStyle;\n            \n            var rect = GUILayoutUtility.GetRect(new GUIContent(soundData.name), style, GUILayout.ExpandWidth(true));\n            \n            // Handle events BEFORE button to capture them\n            Event evt = Event.current;\n            \n            // Handle double-click\n            if (evt.type == EventType.MouseDown && evt.clickCount == 2 && evt.button == 0 && rect.Contains(evt.mousePosition))\n            {\n                StartRename(soundData);\n                evt.Use();\n                return;\n            }\n            \n            // Handle right-click\n            if (evt.type == EventType.ContextClick && rect.Contains(evt.mousePosition))\n            {\n                ShowSoundDataContextMenu(soundData);\n                evt.Use();\n                return;\n            }\n            \n            // Normal button click\n            if (GUI.Button(rect, soundData.name, style))\n            {\n                SelectSoundData(soundData);\n            }\n        }\n\n        private static void DrawRenamingField(SoundData soundData)\n        {\n            GUILayout.BeginHorizontal();\n            \n            GUI.SetNextControlName(\"RenameField\");\n            renamingText = GUILayout.TextField(renamingText, GUILayout.ExpandWidth(true));\n            \n            if (GUILayout.Button(\"✓\", GUILayout.Width(25)))\n            {\n                ConfirmRename(soundData);\n            }\n            \n            if (GUILayout.Button(\"✕\", GUILayout.Width(25)))\n            {\n                CancelRename();\n            }\n            \n            GUILayout.EndHorizontal();\n            \n            HandleRenameFieldEvents();\n        }\n\n        private static void HandleRenameFieldEvents()\n        {\n            Event evt = Event.current;\n            \n            if (evt.type == EventType.KeyDown)\n            {\n                if (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter)\n                {\n                    ConfirmRename(renamingSoundData);\n                    evt.Use();\n                }\n                else if (evt.keyCode == KeyCode.Escape)\n                {\n                    CancelRename();\n                    evt.Use();\n                }\n            }\n            \n            if (isRenaming && GUI.GetNameOfFocusedControl() != \"RenameField\")\n            {\n                GUI.FocusControl(\"RenameField\");\n            }\n        }\n\n        private static void StartRename(SoundData soundData)\n        {\n            renamingSoundData = soundData;\n            renamingText = soundData.name;\n            isRenaming = true;\n            GUI.FocusControl(\"RenameField\");\n        }\n\n        private static void ConfirmRename(SoundData soundData)\n        {\n            if (string.IsNullOrWhiteSpace(renamingText))\n            {\n                EditorUtility.DisplayDialog(\"Invalid Name\", \"Asset name cannot be empty!\", \"OK\");\n                return;\n            }\n            \n            if (renamingText == soundData.name)\n            {\n                CancelRename();\n                return;\n            }\n            \n            string assetPath = AssetDatabase.GetAssetPath(soundData);\n            string errorMessage = AssetDatabase.RenameAsset(assetPath, renamingText);\n            \n            if (!string.IsNullOrEmpty(errorMessage))\n            {\n                EditorUtility.DisplayDialog(\"Rename Failed\", errorMessage, \"OK\");\n            }\n            else\n            {\n                AssetDatabase.SaveAssets();\n                AssetDatabase.Refresh();\n                needsRefresh = true;\n            }\n            \n            CancelRename();\n        }\n\n        private static void CancelRename()\n        {\n            isRenaming = false;\n            renamingSoundData = null;\n            renamingText = \"\";\n            GUI.FocusControl(null);\n        }\n\n        private static void ShowSoundDataContextMenu(SoundData soundData)\n        {\n            GenericMenu menu = new GenericMenu();\n            \n            menu.AddItem(new GUIContent(\"Rename\"), false, () => \n            {\n                StartRename(soundData);\n            });\n            \n            menu.AddSeparator(\"\");\n            \n            menu.AddItem(new GUIContent(\"Ping in Project\"), false, () => \n            {\n                Selection.activeObject = soundData;\n                EditorGUIUtility.PingObject(soundData);\n            });\n            \n            menu.AddItem(new GUIContent(\"Duplicate\"), false, () => \n            {\n                var path = AssetDatabase.GetAssetPath(soundData);\n                var newPath = AssetDatabase.GenerateUniqueAssetPath(path);\n                AssetDatabase.CopyAsset(path, newPath);\n                AssetDatabase.SaveAssets();\n                AssetDatabase.Refresh();\n                needsRefresh = true;\n            });\n            \n            menu.AddSeparator(\"\");\n            \n            menu.AddItem(new GUIContent(\"Delete\"), false, () => \n            {\n                if (EditorUtility.DisplayDialog(\"Delete SoundData\", \n                    $\"Are you sure you want to delete '{soundData.name}'?\", \"Delete\", \"Cancel\"))\n                {\n                    var path = AssetDatabase.GetAssetPath(soundData);\n                    AssetDatabase.DeleteAsset(path);\n                    if (selectedSoundData == soundData)\n                    {\n                        selectedSoundData = null;\n                        DestroyEditor(ref soundDataEditor);\n                    }\n                    AssetDatabase.SaveAssets();\n                    AssetDatabase.Refresh();\n                    needsRefresh = true;\n                }\n            });\n            \n            menu.ShowAsContext();\n        }\n\n        private static void SelectSoundData(SoundData soundData)\n        {\n            if (selectedSoundData != soundData)\n            {\n                selectedSoundData = soundData;\n                DestroyEditor(ref soundDataEditor);\n            }\n        }\n\n        private static void DrawRightExplore()\n        {\n            rightPanelScrollPosition = GUILayout.BeginScrollView(\n                rightPanelScrollPosition, \n                GUILayout.ExpandHeight(true));\n\n            if (selectedSoundData != null)\n            {\n                DrawPingButton();\n                GUILayout.Space(5);\n                DrawSoundDataEditor();\n            }\n            else\n            {\n                GUILayout.Label(\"No SoundData selected\", EditorStyles.centeredGreyMiniLabel);\n            }\n\n            GUILayout.EndScrollView();\n        }\n\n        private static void DrawPingButton()\n        {\n            GUILayout.BeginHorizontal();\n            if (GUILayout.Button(\"Ping Asset\", \n                GUILayout.Width(LayoutConstants.PING_BUTTON_WIDTH)))\n            {\n                EditorGUIUtility.PingObject(selectedSoundData);\n                Selection.activeObject = selectedSoundData;\n            }\n            GUILayout.EndHorizontal();\n        }\n\n        private static void DrawSoundDataEditor()\n        {\n            if (soundDataEditor == null || \n                (soundDataEditor.target as SoundData) != selectedSoundData)\n            {\n                DestroyEditor(ref soundDataEditor);\n                soundDataEditor = UnityEditor.Editor.CreateEditor(selectedSoundData);\n            }\n\n            if (soundDataEditor != null)\n            {\n                if (soundDataEditor is SoundDataEditor sdEditor)\n                {\n                    sdEditor.SetExternalRepaintCallback(hostWindow != null\n                        ? new Action(hostWindow.Repaint)\n                        : null);\n                }\n\n                EditorGUI.BeginChangeCheck();\n                soundDataEditor.OnInspectorGUI();\n                if (EditorGUI.EndChangeCheck())\n                {\n                    EditorUtility.SetDirty(selectedSoundData);\n                }\n            }\n        }\n\n        private static void HandleKeyboardInput()\n        {\n            if (isRenaming)\n                return;\n            \n            Event evt = Event.current;\n            \n            // Accept both KeyDown and KeyUp for better compatibility\n            if (evt.type != EventType.KeyDown && evt.type != EventType.KeyUp)\n                return;\n            \n            // Only process on KeyDown to avoid double-processing\n            if (evt.type != EventType.KeyDown)\n                return;\n            \n            var assets = GetFilteredSoundDataAssets();\n            int currentIndex = assets.IndexOf(selectedSoundData);\n            \n            switch (evt.keyCode)\n            {\n                case KeyCode.F2:\n                    if (selectedSoundData != null)\n                    {\n                        StartRename(selectedSoundData);\n                        evt.Use();\n                        GUI.changed = true;\n                    }\n                    break;\n                \n                case KeyCode.UpArrow:\n                    if (currentIndex > 0)\n                    {\n                        SelectSoundData(assets[currentIndex - 1]);\n                        evt.Use();\n                    }\n                    break;\n                    \n                case KeyCode.DownArrow:\n                    if (currentIndex >= 0 && currentIndex < assets.Count - 1)\n                    {\n                        SelectSoundData(assets[currentIndex + 1]);\n                        evt.Use();\n                    }\n                    break;\n                    \n                case KeyCode.Return:\n                case KeyCode.KeypadEnter:\n                    if (selectedSoundData != null)\n                    {\n                        EditorGUIUtility.PingObject(selectedSoundData);\n                        Selection.activeObject = selectedSoundData;\n                        evt.Use();\n                    }\n                    break;\n                    \n                case KeyCode.Delete:\n                case KeyCode.Backspace:\n                    if (selectedSoundData != null && evt.command == false && evt.control == false)\n                    {\n                        if (EditorUtility.DisplayDialog(\"Delete SoundData\", \n                            $\"Are you sure you want to delete '{selectedSoundData.name}'?\", \"Delete\", \"Cancel\"))\n                        {\n                            var path = AssetDatabase.GetAssetPath(selectedSoundData);\n                            AssetDatabase.DeleteAsset(path);\n                            selectedSoundData = null;\n                            DestroyEditor(ref soundDataEditor);\n                            AssetDatabase.SaveAssets();\n                            AssetDatabase.Refresh();\n                            needsRefresh = true;\n                        }\n                        evt.Use();\n                    }\n                    break;\n            }\n        }\n        #endregion\n        #region Settings Tab\n        private static void DrawSetting(Rect position)\n        {\n            DrawCreateSoundDataSection();\n            DrawSectionSeparator(position);\n            DrawMusicEventSection();\n            DrawSectionSeparator(position);\n            DrawSfxEventSection();\n            DrawSectionSeparator(position);\n            DrawVolumeVariableSection();\n        }\n\n        private static void DrawSectionSeparator(Rect position)\n        {\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            CPUtility.DrawLineLastRectY(\n                LayoutConstants.LINE_THICKNESS, \n                ConstantControlPanel.POSITION_X_START_CONTENT, \n                position.width);\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n        }\n\n        private static void DrawCreateSoundDataSection()\n        {\n            if (GUILayout.Button(\"Create Sound Data\"))\n            {\n                AudioWindowEditor.CreateSoundData();\n                needsRefresh = true;\n            }\n        }\n\n        private static void DrawMusicEventSection()\n        {\n            CPUtility.DrawHeader(\"Music Event\");\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            \n            DrawButton(\"Create Play Music Event\", AudioWindowEditor.CreatePlayMusicEvent);\n            DrawButton(\"Create Pause Music Event\", AudioWindowEditor.CreatePauseMusicEvent);\n            DrawButton(\"Create Resume Music Event\", AudioWindowEditor.CreateResumeMusicEvent);\n            DrawButton(\"Create Stop Music Event\", AudioWindowEditor.CreateStopMusicEvent);\n        }\n\n        private static void DrawSfxEventSection()\n        {\n            CPUtility.DrawHeader(\"Sfx Event\");\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            \n            DrawButton(\"Create Play Sfx Event\", AudioWindowEditor.CreatePlaySfxEvent);\n            DrawButton(\"Create Pause Sfx Event\", AudioWindowEditor.CreatePauseSfxEvent);\n            DrawButton(\"Create Resume Sfx Event\", AudioWindowEditor.CreateResumeSfxEvent);\n            DrawButton(\"Create Finish Sfx Event\", AudioWindowEditor.CreateFinishSfxEvent);\n            DrawButton(\"Create Stop Sfx Event\", AudioWindowEditor.CreateStopSfxEvent);\n            DrawButton(\"Create Stop All Sfx Event\", AudioWindowEditor.CreateStopAllSfxEvent);\n        }\n\n        private static void DrawVolumeVariableSection()\n        {\n            CPUtility.DrawHeader(\"Volume Changed Variable\");\n            GUILayout.Space(LayoutConstants.HEADER_SPACING);\n            \n            DrawButton(\"Create Music Volume Variable\", AudioWindowEditor.CreateMusicVolume);\n            DrawButton(\"Create Sfx Volume Variable\", AudioWindowEditor.CreateSfxVolume);\n        }\n\n        private static void DrawButton(string label, System.Action onClick)\n        {\n            if (GUILayout.Button(label))\n            {\n                onClick?.Invoke();\n            }\n        }\n        #endregion\n    }\n}\n\n\n\n\n\n"
  },
  {
    "path": "VirtueSky/ControlPanel/CPAudioDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 75f998153cb84b05b39fde9bba92e154\ntimeCreated: 1704943417"
  },
  {
    "path": "VirtueSky/ControlPanel/CPExtensionsDrawer.cs",
    "content": "using System.Diagnostics;\nusing System.IO;\nusing UnityEditor;\nusing UnityEditor.Android;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPExtensionsDrawer\n    {\n        public static void OnDrawExtensions(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.Extensions, \"Extensions\");\n#if UNITY_ANDROID\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Open Sdk\"))\n            {\n                OpenSdkPath();\n            }\n\n            if (GUILayout.Button(\"Open Jdk\"))\n            {\n                OpenJdkPath();\n            }\n\n            if (GUILayout.Button(\"Open Ndk\"))\n            {\n                OpenNdkPath();\n            }\n\n            if (GUILayout.Button(\"Open Gradle\"))\n            {\n                OpenGradlePath();\n            }\n\n            if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows)\n            {\n                GUILayout.Space(10);\n                CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n                GUILayout.Space(10);\n                EditorGUILayout.HelpBox(\"Monitor only works on java sdk 8\", MessageType.Warning);\n                if (GUILayout.Button(\"Open Monitor\"))\n                {\n                    OpenMonitor();\n                }\n            }\n#endif\n            GUILayout.EndVertical();\n        }\n\n#if UNITY_ANDROID\n\n        static void OpenSdkPath()\n        {\n            var path = $\"{AndroidExternalToolsSettings.sdkRootPath}/\";\n            switch (SystemInfo.operatingSystemFamily)\n            {\n                case OperatingSystemFamily.Windows:\n                    FileExtension.OpenFolderInExplorer(path);\n                    break;\n                case OperatingSystemFamily.MacOSX:\n                    FileExtension.OpenFolderInFinder(path);\n                    break;\n            }\n        }\n\n        static void OpenJdkPath()\n        {\n            var path = $\"{AndroidExternalToolsSettings.jdkRootPath}/\";\n            switch (SystemInfo.operatingSystemFamily)\n            {\n                case OperatingSystemFamily.Windows:\n                    FileExtension.OpenFolderInExplorer(path);\n                    break;\n                case OperatingSystemFamily.MacOSX:\n                    FileExtension.OpenFolderInFinder(path);\n                    break;\n            }\n        }\n\n        static void OpenNdkPath()\n        {\n            var path = $\"{AndroidExternalToolsSettings.ndkRootPath}/\";\n            switch (SystemInfo.operatingSystemFamily)\n            {\n                case OperatingSystemFamily.Windows:\n                    FileExtension.OpenFolderInExplorer(path);\n                    break;\n                case OperatingSystemFamily.MacOSX:\n                    FileExtension.OpenFolderInFinder(path);\n                    break;\n            }\n        }\n\n        static void OpenGradlePath()\n        {\n            var path = $\"{AndroidExternalToolsSettings.gradlePath}/\";\n            switch (SystemInfo.operatingSystemFamily)\n            {\n                case OperatingSystemFamily.Windows:\n                    FileExtension.OpenFolderInExplorer(path);\n                    break;\n                case OperatingSystemFamily.MacOSX:\n                    FileExtension.OpenFolderInFinder(path);\n                    break;\n            }\n        }\n\n        static void OpenMonitor()\n        {\n            string path = $\"{AndroidExternalToolsSettings.sdkRootPath}/tools/monitor.bat\";\n            if (File.Exists(path))\n            {\n                Process process = new Process();\n                process.StartInfo.FileName = path;\n                process.StartInfo.Verb = \"runas\";\n                process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;\n                process.Start();\n            }\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPExtensionsDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3eebf2e8a6bc4f81b7990a906df66bc7\ntimeCreated: 1709182260"
  },
  {
    "path": "VirtueSky/ControlPanel/CPFirebaseDrawer.cs",
    "content": "using System.Diagnostics;\nusing System.IO;\nusing UnityEditor;\nusing UnityEditor.Android;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPFirebaseDrawer\n    {\n        private static bool isShowInstallRemoteConfig = true;\n        private static bool isShowInstallAnalytic = true;\n        private static Vector2 scroll = Vector2.zero;\n        private static bool isCustomPackageName;\n        private static string packageName;\n\n        public static void OnDrawFirebase(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.Firebase, \"Firebase\");\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n            DrawInstallFirebase(position);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define Symbols\");\n            GUILayout.Space(10);\n#if !VIRTUESKY_FIREBASE\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_FIREBASE} for Firebase App\",\n                MessageType.Info);\n#endif\n\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE);\n#if !VIRTUESKY_FIREBASE_REMOTECONFIG\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG} for Firebase Remote Config to use\",\n                MessageType.Info);\n#endif\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG);\n#if !VIRTUESKY_FIREBASE_ANALYTIC\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC} for Firebase Analytic to use\",\n                MessageType.Info);\n#endif\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC);\n            GUILayout.Space(10);\n            DrawTracking(position);\n\n#if UNITY_ANDROID\n            CPUtility.GuiLine(2);\n            DrawDebugView();\n#endif\n            GUILayout.Space(10);\n            EditorGUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n\n        static void DrawInstallFirebase(Rect position)\n        {\n            GUILayout.Space(20);\n            isShowInstallRemoteConfig =\n                GUILayout.Toggle(isShowInstallRemoteConfig, \"Install Firebase Remote Config And Dependency\");\n            GUILayout.Space(10);\n            if (isShowInstallRemoteConfig)\n            {\n                CPUtility.DrawButtonInstallPackage(\"Install Firebase Remote Config\", \"Remove Firebase Remote Config\",\n                    ConstantPackage.PackageNameFirebaseRemoteConfig, ConstantPackage.MaxVersionFirebaseRemoteConfig);\n                CPUtility.DrawButtonInstallPackage(\"Install Firebase App\", \"Remove Firebase App\",\n                    ConstantPackage.PackageNameFirebaseApp, ConstantPackage.MaxVersionFirebaseApp);\n                CPUtility.DrawButtonInstallPackage(\"Install Google External Dependency Manager\",\n                    \"Remove Google External Dependency Manager\",\n                    ConstantPackage.PackageNameGGExternalDependencyManager,\n                    ConstantPackage.MaxVersionGGExternalDependencyManager);\n            }\n\n            GUILayout.Space(10);\n            isShowInstallAnalytic = GUILayout.Toggle(isShowInstallAnalytic, \"Install Firebase Analytic And Dependency\");\n            GUILayout.Space(10);\n            if (isShowInstallAnalytic)\n            {\n                CPUtility.DrawButtonInstallPackage(\"Install Firebase Analytics\", \"Remove Firebase Analytics\",\n                    ConstantPackage.PackageNameFirebaseAnalytics, ConstantPackage.MaxVersionFirebaseAnalytics);\n                CPUtility.DrawButtonInstallPackage(\"Install Firebase App\", \"Remove Firebase App\",\n                    ConstantPackage.PackageNameFirebaseApp, ConstantPackage.MaxVersionFirebaseApp);\n                CPUtility.DrawButtonInstallPackage(\"Install Google External Dependency Manager\",\n                    \"Remove Google External Dependency Manager\",\n                    ConstantPackage.PackageNameGGExternalDependencyManager,\n                    ConstantPackage.MaxVersionGGExternalDependencyManager);\n                GUILayout.Space(10);\n            }\n        }\n\n        static void DrawTracking(Rect position)\n        {\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Firebase Tracking\");\n            GUILayout.Space(10);\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase No Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseNoParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase 1 Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseOneParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase 2 Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseTwoParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase 3 Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseThreeParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase 4 Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseFourParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase 5 Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseFiveParam();\n            }\n\n            if (GUILayout.Button(\"Create Scriptable Tracking Firebase 6 Param\"))\n            {\n                TrackingWindowEditor.CreateLogEventFirebaseSixParam();\n            }\n\n            GUILayout.Space(10);\n        }\n\n#if UNITY_ANDROID\n        static void DrawDebugView()\n        {\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Debug View\");\n            GUILayout.Space(10);\n            isCustomPackageName = EditorGUILayout.Toggle(\"Custom Package Name: \", isCustomPackageName);\n            if (isCustomPackageName)\n            {\n                GUI.enabled = true;\n            }\n            else\n            {\n                packageName = Application.identifier;\n                GUI.enabled = false;\n            }\n\n            packageName = EditorGUILayout.TextField(\"Package Name: \", packageName);\n            GUI.enabled = true;\n            GUILayout.BeginHorizontal();\n            if (GUILayout.Button(\"Run Debug View\", GUILayout.Width(400)))\n            {\n                SetDebugView(packageName);\n            }\n\n            if (GUILayout.Button(\"Set None Debug View\"))\n            {\n                SetDebugView(\".none.\");\n            }\n\n            GUILayout.EndHorizontal();\n        }\n\n        static void SetDebugView(string package)\n        {\n            var fileName = $\"{AndroidExternalToolsSettings.sdkRootPath}/platform-tools/adb\";\n            var arguments = $\"shell setprop debug.firebase.analytics.app {package}\";\n            var startInfo = new ProcessStartInfo\n            {\n                FileName = fileName,\n                UseShellExecute = false,\n                RedirectStandardOutput = true,\n                CreateNoWindow = true,\n                Arguments = arguments,\n            };\n\n            var process = Process.Start(startInfo);\n            process!.WaitForExit();\n            UnityEngine.Debug.Log($\"{fileName} {arguments}\");\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPFirebaseDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5d84391d37284f243863d41a6106102b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ControlPanel/CPFolderIconDrawer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing Virtuesky.FolderIcon.Editor;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPFolderIconDrawer\n    {\n        private static UnityEditor.Editor _editor;\n        private static FolderIconSettings _settings;\n        private static Vector2 scroll = Vector2.zero;\n\n        public static void OnEnable()\n        {\n            Init();\n        }\n\n        private static void Init()\n        {\n            if (_editor != null)\n            {\n                _editor = null;\n            }\n\n            _settings = CreateAsset.GetScriptableAsset<FolderIconSettings>();\n            _editor = UnityEditor.Editor.CreateEditor(_settings);\n        }\n\n        public static void OnDrawFolderIcon()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.FolderIcon, \"Folder Icon\");\n            GUILayout.Space(10);\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n            if (_settings == null)\n            {\n                if (GUILayout.Button(\"Create FolderIconSetting\"))\n                {\n                    _settings = CreateAsset.CreateAndGetScriptableAsset<FolderIconSettings>(\n                        \"Assets/_Sunflower/Editor/FolderIconSettings\", useDefaultPath: false);\n                    Init();\n                }\n            }\n            else\n            {\n                if (_editor == null)\n                {\n                    EditorGUILayout.HelpBox(\"Couldn't create the settings editor.\",\n                        MessageType.Error);\n                    return;\n                }\n                else\n                {\n                    _editor.OnInspectorGUI();\n                    GUILayout.Space(10);\n\n                    if (_settings.enableFolderIcons)\n                    {\n                        if (GUILayout.Button(\"Clear cache\"))\n                        {\n                            _settings.ClearCache();\n                        }\n\n                        GUILayout.Space(10);\n                        if (GUILayout.Button(\"Import texture icon folder\"))\n                        {\n                            AssetDatabase.ImportPackage(\n                                FileExtension.GetPathFileInCurrentEnvironment(\n                                    \"VirtueSky/FolderIcon/Editor/PackageIcon/icon_folder.unitypackage\"), false);\n                        }\n                    }\n                }\n            }\n\n            EditorGUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPFolderIconDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 32daceff059c4ada87f6012ac05a1b19\ntimeCreated: 1722325833"
  },
  {
    "path": "VirtueSky/ControlPanel/CPGameServiceDrawer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPGameServiceDrawer\n    {\n        public static void OnDrawGameService()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.GameService, \"Game Service\");\n            GUILayout.Space(10);\n\n            CPUtility.DrawButtonInstallPackage(\"Install Apple Sign In\", \"Remove Apple Sign In\",\n                ConstantPackage.PackageNameAppleSignIn, ConstantPackage.MaxVersionAppleSignIn);\n\n            if (GUILayout.Button(\"Install Google Play Game Service\", GUILayout.Width(400)))\n            {\n                AssetDatabase.ImportPackage(\n                    FileExtension.GetPathFileInCurrentEnvironment(\n                        \"VirtueSky/Utils/Editor/UnityPackage/google-play-game.unitypackage\"), false);\n            }\n\n            GUILayout.Space(10);\n            CPUtility.GuiLine();\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define symbols\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_GPGS);\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPGameServiceDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 39779f060a5248b88ca37991f3398939\ntimeCreated: 1706698019"
  },
  {
    "path": "VirtueSky/ControlPanel/CPHierarchyDrawer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\nusing UnityEditor;\nusing UnityEngine;\n\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPHierarchyDrawer\n    {\n        public static void OnDrawQHierarchyEvent(Rect posittion, EditorWindow window)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.Hierarchy, \"Hierarchy\");\n            GUILayout.Space(10);\n            OnGUI(posittion, window);\n            GUILayout.EndVertical();\n        }\n\n        private static void init(EditorWindow window)\n        {\n            HierarchySettings.getInstance().inited = true;\n            HierarchySettings.getInstance().isProSkin = EditorGUIUtility.isProSkin;\n            HierarchySettings.getInstance().separatorColor =\n                HierarchySettings.getInstance().isProSkin\n                    ? new Color(0.18f, 0.18f, 0.18f)\n                    : new Color(0.59f, 0.59f, 0.59f);\n            HierarchySettings.getInstance().yellowColor =\n                HierarchySettings.getInstance().isProSkin\n                    ? new Color(1.00f, 0.90f, 0.40f)\n                    : new Color(0.31f, 0.31f, 0.31f);\n            HierarchySettings.getInstance().checkBoxChecked = HierarchyResources.getInstance()\n                .getTexture(HierarchyTexture.HierarchyCheckBoxChecked);\n            HierarchySettings.getInstance().checkBoxUnchecked =\n                HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyCheckBoxUnchecked);\n            HierarchySettings.getInstance().restoreButtonTexture = HierarchyResources.getInstance()\n                .getTexture(HierarchyTexture.HierarchyRestoreButton);\n            HierarchySettings.getInstance().componentsOrderList = new HierarchyComponentsOrderList(window);\n        }\n\n        // GUI\n        public static void OnGUI(Rect position, EditorWindow window)\n        {\n            if (!HierarchySettings.getInstance().inited ||\n                HierarchySettings.getInstance().isProSkin != EditorGUIUtility.isProSkin)\n                init(window);\n\n            HierarchySettings.getInstance().indentLevel = 8;\n            HierarchySettings.getInstance().scrollPosition =\n                EditorGUILayout.BeginScrollView(HierarchySettings.getInstance().scrollPosition);\n            {\n                Rect targetRect = EditorGUILayout.GetControlRect(GUILayout.Height(0));\n                if (Event.current.type == EventType.Repaint)\n                    HierarchySettings.getInstance().totalWidth = targetRect.width + 8;\n\n                HierarchySettings.getInstance().lastRect = new Rect(0, 1, 0, 0);\n\n                // COMPONENTS\n                drawSection(\"COMPONENTS SETTINGS\");\n                float sectionStartY = HierarchySettings.getInstance().lastRect.y +\n                                      HierarchySettings.getInstance().lastRect.height;\n\n                drawTreeMapComponentSettings();\n                drawSeparator();\n                drawMonoBehaviourIconComponentSettings();\n                drawSeparator();\n                drawSeparatorComponentSettings();\n                drawSeparator();\n                drawVisibilityComponentSettings();\n                drawSeparator();\n                drawLockComponentSettings();\n                drawSeparator();\n                drawStaticComponentSettings();\n                drawSeparator();\n                drawErrorComponentSettings();\n                drawSeparator();\n                drawRendererComponentSettings();\n                drawSeparator();\n                drawPrefabComponentSettings();\n                drawSeparator();\n                drawTagLayerComponentSettings();\n                drawSeparator();\n                drawColorComponentSettings();\n                drawSeparator();\n                drawGameObjectIconComponentSettings();\n                drawSeparator();\n                drawTagIconComponentSettings();\n                drawSeparator();\n                drawLayerIconComponentSettings();\n                drawSeparator();\n                drawChildrenCountComponentSettings();\n                drawSeparator();\n                drawVerticesAndTrianglesCountComponentSettings();\n                drawSeparator();\n                drawComponentsComponentSettings();\n                drawLeftLine(sectionStartY,\n                    HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height,\n                    HierarchySettings.getInstance().separatorColor);\n\n                // ORDER\n                drawSection(\"ORDER OF COMPONENTS\");\n                sectionStartY = HierarchySettings.getInstance().lastRect.y +\n                                HierarchySettings.getInstance().lastRect.height;\n                drawSpace(8);\n                drawOrderSettings(position, window);\n                drawSpace(6);\n                drawLeftLine(sectionStartY,\n                    HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height,\n                    HierarchySettings.getInstance().separatorColor);\n\n                // ADDITIONAL\n                drawSection(\"ADDITIONAL SETTINGS\");\n                sectionStartY = HierarchySettings.getInstance().lastRect.y +\n                                HierarchySettings.getInstance().lastRect.height;\n                drawSpace(3);\n                drawAdditionalSettings();\n                drawLeftLine(sectionStartY,\n                    HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height + 4,\n                    HierarchySettings.getInstance().separatorColor);\n\n                HierarchySettings.getInstance().indentLevel -= 8;\n            }\n\n            EditorGUILayout.EndScrollView();\n        }\n\n        // COMPONENTS\n        private static void drawTreeMapComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Hierarchy Tree\", HierarchySetting.TreeMapShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.TreeMapColor);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TreeMapEnhanced);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TreeMapTransparentBackground);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5);\n                drawSpace(4);\n                drawColorPicker(\"Tree color\", HierarchySetting.TreeMapColor);\n                drawCheckBoxRight(\"Transparent background\", HierarchySetting.TreeMapTransparentBackground);\n                drawCheckBoxRight(\"Enhanced (\\\"Transform Sort\\\" only)\", HierarchySetting.TreeMapEnhanced);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawMonoBehaviourIconComponentSettings()\n        {\n            if (drawComponentCheckBox(\"MonoBehaviour Icon\", HierarchySetting.MonoBehaviourIconShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.MonoBehaviourIconShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.MonoBehaviourIconColor);\n                    HierarchySettings.getInstance()\n                        .restore(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.MonoBehaviourIconShowDuringPlayMode);\n                drawColorPicker(\"Icon color\", HierarchySetting.MonoBehaviourIconColor);\n                drawCheckBoxRight(\"Ignore Unity MonoBehaviours\",\n                    HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawSeparatorComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Separator\", HierarchySetting.SeparatorShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.SeparatorColor);\n                    HierarchySettings.getInstance().restore(HierarchySetting.SeparatorShowRowShading);\n                    HierarchySettings.getInstance().restore(HierarchySetting.SeparatorOddRowShadingColor);\n                    HierarchySettings.getInstance().restore(HierarchySetting.SeparatorEvenRowShadingColor);\n                }\n\n                bool rowShading =\n                    HierarchySettings.getInstance().get<bool>(HierarchySetting.SeparatorShowRowShading);\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * (rowShading ? 4 : 2) + 5);\n                drawSpace(4);\n                drawColorPicker(\"Separator Color\", HierarchySetting.SeparatorColor);\n                drawCheckBoxRight(\"Row shading\", HierarchySetting.SeparatorShowRowShading);\n                if (rowShading)\n                {\n                    drawColorPicker(\"Even row shading color\",\n                        HierarchySetting.SeparatorEvenRowShadingColor);\n                    drawColorPicker(\"Odd row shading color\", HierarchySetting.SeparatorOddRowShadingColor);\n                }\n\n                drawSpace(1);\n            }\n        }\n\n        private static void drawVisibilityComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Visibility\", HierarchySetting.VisibilityShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.VisibilityShowDuringPlayMode);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.VisibilityShowDuringPlayMode);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawLockComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Lock\", HierarchySetting.LockShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.LockShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.LockPreventSelectionOfLockedObjects);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.LockShowDuringPlayMode);\n                drawCheckBoxRight(\"Prevent selection of locked objects\",\n                    HierarchySetting.LockPreventSelectionOfLockedObjects);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawStaticComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Static\", HierarchySetting.StaticShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.StaticShowDuringPlayMode);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.StaticShowDuringPlayMode);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawErrorComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Error\", HierarchySetting.ErrorShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowIconOnParent);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowForDisabledComponents);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowForDisabledGameObjects);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowScriptIsMissing);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowReferenceIsMissing);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowReferenceIsNull);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowStringIsEmpty);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowMissingEventMethod);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ErrorIgnoreString);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 12 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.ErrorShowDuringPlayMode);\n                drawCheckBoxRight(\"Show error icon up of hierarchy (very slow)\",\n                    HierarchySetting.ErrorShowIconOnParent);\n                drawCheckBoxRight(\"Show error icon for disabled components\",\n                    HierarchySetting.ErrorShowForDisabledComponents);\n                drawCheckBoxRight(\"Show error icon for disabled GameObjects\",\n                    HierarchySetting.ErrorShowForDisabledGameObjects);\n                drawLabel(\"Show error icon for the following:\");\n                HierarchySettings.getInstance().indentLevel += 16;\n                drawCheckBoxRight(\"- script is missing\", HierarchySetting.ErrorShowScriptIsMissing);\n                drawCheckBoxRight(\"- reference is missing\", HierarchySetting.ErrorShowReferenceIsMissing);\n                drawCheckBoxRight(\"- reference is null\", HierarchySetting.ErrorShowReferenceIsNull);\n                drawCheckBoxRight(\"- string is empty\", HierarchySetting.ErrorShowStringIsEmpty);\n                drawCheckBoxRight(\"- callback of event is missing (very slow)\",\n                    HierarchySetting.ErrorShowMissingEventMethod);\n                drawCheckBoxRight(\"- tag or layer is undefined\",\n                    HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined);\n                HierarchySettings.getInstance().indentLevel -= 16;\n                drawTextField(\"Ignore packages/classes\", HierarchySetting.ErrorIgnoreString);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawRendererComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Renderer\", HierarchySetting.RendererShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.RendererShowDuringPlayMode);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.RendererShowDuringPlayMode);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawPrefabComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Prefab\", HierarchySetting.PrefabShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.PrefabShowBreakedPrefabsOnly);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show icon for broken prefabs only\",\n                    HierarchySetting.PrefabShowBreakedPrefabsOnly);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawTagLayerComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Tag And Layer\", HierarchySetting.TagAndLayerShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeShowType);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerType);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeValueType);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeValuePixel);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerSizeValuePercent);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerAligment);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerLabelSize);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerLabelAlpha);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerTagLabelColor);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagAndLayerLayerLabelColor);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 10 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.TagAndLayerShowDuringPlayMode);\n                drawEnum(\"Show\", HierarchySetting.TagAndLayerSizeShowType,\n                    typeof(HierarchyTagAndLayerShowType));\n                drawEnum(\"Show tag and layer\", HierarchySetting.TagAndLayerType,\n                    typeof(HierarchyTagAndLayerType));\n\n                HierarchyTagAndLayerSizeType newTagAndLayerSizeValueType =\n                    (HierarchyTagAndLayerSizeType)drawEnum(\"Unit of width\",\n                        HierarchySetting.TagAndLayerSizeValueType, typeof(HierarchyTagAndLayerSizeType));\n\n                if (newTagAndLayerSizeValueType == HierarchyTagAndLayerSizeType.Pixel)\n                    drawIntSlider(\"Width in pixels\", HierarchySetting.TagAndLayerSizeValuePixel, 5, 250);\n                else\n                    drawFloatSlider(\"Percentage width\", HierarchySetting.TagAndLayerSizeValuePercent, 0,\n                        0.5f);\n\n                drawEnum(\"Alignment\", HierarchySetting.TagAndLayerAligment,\n                    typeof(HierarchyTagAndLayerAligment));\n                drawEnum(\"Label size\", HierarchySetting.TagAndLayerLabelSize,\n                    typeof(HierarchyTagAndLayerLabelSize));\n                drawFloatSlider(\"Label alpha if default\", HierarchySetting.TagAndLayerLabelAlpha, 0, 1.0f);\n                drawColorPicker(\"Tag label color\", HierarchySetting.TagAndLayerTagLabelColor);\n                drawColorPicker(\"Layer label color\", HierarchySetting.TagAndLayerLayerLabelColor);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawColorComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Color\", HierarchySetting.ColorShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.ColorShowDuringPlayMode);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.ColorShowDuringPlayMode);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawGameObjectIconComponentSettings()\n        {\n            if (drawComponentCheckBox(\"GameObject Icon\", HierarchySetting.GameObjectIconShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.GameObjectIconShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.GameObjectIconSize);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.GameObjectIconShowDuringPlayMode);\n                drawEnum(\"Icon size\", HierarchySetting.GameObjectIconSize, typeof(HierarchySizeAll));\n                drawSpace(1);\n            }\n        }\n\n        private static void drawTagIconComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Tag Icon\", HierarchySetting.TagIconShow))\n            {\n                string[] tags = UnityEditorInternal.InternalEditorUtility.tags;\n\n                bool showTagIconList =\n                    HierarchySettings.getInstance().get<bool>(HierarchySetting.TagIconListFoldout);\n\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagIconShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.TagIconSize);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width,\n                    18 * 3 + (showTagIconList ? 18 * tags.Length : 0) + 4 + 5);\n\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.TagIconShowDuringPlayMode);\n                drawEnum(\"Icon size\", HierarchySetting.TagIconSize, typeof(HierarchySizeAll));\n                if (drawFoldout(\"Tag icon list\", HierarchySetting.TagIconListFoldout))\n                {\n                    List<TagTexture> tagTextureList = TagTexture.loadTagTextureList();\n\n                    bool changed = false;\n                    for (int i = 0; i < tags.Length; i++)\n                    {\n                        string tag = tags[i];\n                        TagTexture tagTexture = tagTextureList.Find(t => t.tag == tag);\n                        Texture2D newTexture = (Texture2D)EditorGUI.ObjectField(\n                            getControlRect(0, 16, 34 + 16, 6),\n                            tag, tagTexture == null ? null : tagTexture.texture, typeof(Texture2D),\n                            false);\n                        if (newTexture != null && tagTexture == null)\n                        {\n                            TagTexture newTagTexture = new TagTexture(tag, newTexture);\n                            tagTextureList.Add(newTagTexture);\n\n                            changed = true;\n                        }\n                        else if (newTexture == null && tagTexture != null)\n                        {\n                            tagTextureList.Remove(tagTexture);\n                            changed = true;\n                        }\n                        else if (tagTexture != null && tagTexture.texture != newTexture)\n                        {\n                            tagTexture.texture = newTexture;\n                            changed = true;\n                        }\n\n                        drawSpace(i == tags.Length - 1 ? 2 : 2);\n                    }\n\n                    if (changed)\n                    {\n                        TagTexture.saveTagTextureList(HierarchySetting.TagIconList, tagTextureList);\n                        EditorApplication.RepaintHierarchyWindow();\n                    }\n                }\n\n                drawSpace(1);\n            }\n        }\n\n        private static void drawLayerIconComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Layer Icon\", HierarchySetting.LayerIconShow))\n            {\n                string[] layers = UnityEditorInternal.InternalEditorUtility.layers;\n\n                bool showLayerIconList =\n                    HierarchySettings.getInstance().get<bool>(HierarchySetting.LayerIconListFoldout);\n\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.LayerIconShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.LayerIconSize);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width,\n                    18 * 3 + (showLayerIconList ? 18 * layers.Length : 0) + 4 + 5);\n\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.LayerIconShowDuringPlayMode);\n                drawEnum(\"Icon size\", HierarchySetting.LayerIconSize, typeof(HierarchySizeAll));\n                if (drawFoldout(\"Layer icon list\", HierarchySetting.LayerIconListFoldout))\n                {\n                    List<LayerTexture> layerTextureList = LayerTexture.loadLayerTextureList();\n\n                    bool changed = false;\n                    for (int i = 0; i < layers.Length; i++)\n                    {\n                        string layer = layers[i];\n                        LayerTexture layerTexture = layerTextureList.Find(t => t.layer == layer);\n                        Texture2D newTexture = (Texture2D)EditorGUI.ObjectField(\n                            getControlRect(0, 16, 34 + 16, 6),\n                            layer, layerTexture == null ? null : layerTexture.texture,\n                            typeof(Texture2D), false);\n                        if (newTexture != null && layerTexture == null)\n                        {\n                            LayerTexture newLayerTexture = new LayerTexture(layer, newTexture);\n                            layerTextureList.Add(newLayerTexture);\n\n                            changed = true;\n                        }\n                        else if (newTexture == null && layerTexture != null)\n                        {\n                            layerTextureList.Remove(layerTexture);\n                            changed = true;\n                        }\n                        else if (layerTexture != null && layerTexture.texture != newTexture)\n                        {\n                            layerTexture.texture = newTexture;\n                            changed = true;\n                        }\n\n                        drawSpace(i == layers.Length - 1 ? 2 : 2);\n                    }\n\n                    if (changed)\n                    {\n                        LayerTexture.saveLayerTextureList(HierarchySetting.LayerIconList,\n                            layerTextureList);\n                        EditorApplication.RepaintHierarchyWindow();\n                    }\n                }\n\n                drawSpace(1);\n            }\n        }\n\n        private static void drawChildrenCountComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Children Count\", HierarchySetting.ChildrenCountShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.ChildrenCountShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ChildrenCountLabelSize);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ChildrenCountLabelColor);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.ChildrenCountShowDuringPlayMode);\n                drawEnum(\"Label size\", HierarchySetting.ChildrenCountLabelSize, typeof(HierarchySize));\n                drawColorPicker(\"Label color\", HierarchySetting.ChildrenCountLabelColor);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawVerticesAndTrianglesCountComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Vertices And Triangles Count\",\n                    HierarchySetting.VerticesAndTrianglesShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance()\n                        .restore(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.VerticesAndTrianglesShowVertices);\n                    HierarchySettings.getInstance().restore(HierarchySetting.VerticesAndTrianglesShowTriangles);\n                    HierarchySettings.getInstance()\n                        .restore(HierarchySetting.VerticesAndTrianglesCalculateTotalCount);\n                    HierarchySettings.getInstance().restore(HierarchySetting.VerticesAndTrianglesLabelSize);\n                    HierarchySettings.getInstance()\n                        .restore(HierarchySetting.VerticesAndTrianglesVerticesLabelColor);\n                    HierarchySettings.getInstance()\n                        .restore(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 7 + 5);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.VerticesAndTrianglesShowDuringPlayMode);\n                if (drawCheckBoxRight(\"Show vertices count\",\n                        HierarchySetting.VerticesAndTrianglesShowVertices))\n                {\n                    if (HierarchySettings.getInstance()\n                            .get<bool>(HierarchySetting.VerticesAndTrianglesShowVertices) == false &&\n                        HierarchySettings.getInstance()\n                            .get<bool>(HierarchySetting.VerticesAndTrianglesShowTriangles) == false)\n                        HierarchySettings.getInstance()\n                            .set(HierarchySetting.VerticesAndTrianglesShowTriangles, true);\n                }\n\n                if (drawCheckBoxRight(\"Show triangles count (very slow)\",\n                        HierarchySetting.VerticesAndTrianglesShowTriangles))\n                {\n                    if (HierarchySettings.getInstance()\n                            .get<bool>(HierarchySetting.VerticesAndTrianglesShowVertices) == false &&\n                        HierarchySettings.getInstance()\n                            .get<bool>(HierarchySetting.VerticesAndTrianglesShowTriangles) == false)\n                        HierarchySettings.getInstance()\n                            .set(HierarchySetting.VerticesAndTrianglesShowVertices, true);\n                }\n\n                drawCheckBoxRight(\"Calculate the count including children (very slow)\",\n                    HierarchySetting.VerticesAndTrianglesCalculateTotalCount);\n                drawEnum(\"Label size\", HierarchySetting.VerticesAndTrianglesLabelSize,\n                    typeof(HierarchySize));\n                drawColorPicker(\"Vertices label color\",\n                    HierarchySetting.VerticesAndTrianglesVerticesLabelColor);\n                drawColorPicker(\"Triangles label color\",\n                    HierarchySetting.VerticesAndTrianglesTrianglesLabelColor);\n                drawSpace(1);\n            }\n        }\n\n        private static void drawComponentsComponentSettings()\n        {\n            if (drawComponentCheckBox(\"Components\", HierarchySetting.ComponentsShow))\n            {\n                Rect rect = getControlRect(0, 0);\n                if (drawRestore())\n                {\n                    HierarchySettings.getInstance().restore(HierarchySetting.ComponentsShowDuringPlayMode);\n                    HierarchySettings.getInstance().restore(HierarchySetting.ComponentsIconSize);\n                }\n\n                drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 6);\n                drawSpace(4);\n                drawCheckBoxRight(\"Show component during play mode\",\n                    HierarchySetting.ComponentsShowDuringPlayMode);\n                drawEnum(\"Icon size\", HierarchySetting.ComponentsIconSize, typeof(HierarchySizeAll));\n                drawTextField(\"Ignore packages/classes\", HierarchySetting.ComponentsIgnore);\n                drawSpace(2);\n            }\n        }\n\n        // COMPONENTS ORDER\n        private static void drawOrderSettings(Rect position, EditorWindow window)\n        {\n            if (drawRestore())\n            {\n                HierarchySettings.getInstance().restore(HierarchySetting.ComponentsOrder);\n            }\n\n            HierarchySettings.getInstance().indentLevel += 4;\n\n            string componentOrder = HierarchySettings.getInstance().get<string>(HierarchySetting.ComponentsOrder);\n            string[] componentIds = componentOrder.Split(';');\n\n            Rect rect = getControlRect(position.width, 17 * componentIds.Length + 10, 0, 0);\n            if (HierarchySettings.getInstance().componentsOrderList == null)\n                HierarchySettings.getInstance().componentsOrderList = new HierarchyComponentsOrderList(window);\n            HierarchySettings.getInstance().componentsOrderList.draw(rect, componentIds);\n\n            HierarchySettings.getInstance().indentLevel -= 4;\n        }\n\n        // ADDITIONAL SETTINGS\n        private static void drawAdditionalSettings()\n        {\n            if (drawRestore())\n            {\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalHideIconsIfNotFit);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalIdentation);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalShowModifierWarning);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalBackgroundColor);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalActiveColor);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalInactiveColor);\n                HierarchySettings.getInstance().restore(HierarchySetting.AdditionalSpecialColor);\n            }\n\n            drawSpace(4);\n            drawCheckBoxRight(\"Show QHierarchyObjectList GameObject\",\n                HierarchySetting.AdditionalShowHiddenQHierarchyObjectList);\n            drawCheckBoxRight(\"Hide icons if not fit\", HierarchySetting.AdditionalHideIconsIfNotFit);\n            drawIntSlider(\"Right indent\", HierarchySetting.AdditionalIdentation, 0, 500);\n            drawCheckBoxRight(\"Show warning when using modifiers + click\",\n                HierarchySetting.AdditionalShowModifierWarning);\n            drawColorPicker(\"Background color\", HierarchySetting.AdditionalBackgroundColor);\n            drawColorPicker(\"Active color\", HierarchySetting.AdditionalActiveColor);\n            drawColorPicker(\"Inactive color\", HierarchySetting.AdditionalInactiveColor);\n            drawColorPicker(\"Special color\", HierarchySetting.AdditionalSpecialColor);\n            drawSpace(1);\n        }\n\n        // PRIVATE\n        private static void drawSection(string title)\n        {\n            Rect rect = getControlRect(0, 24, -3, 0);\n            rect.width *= 2;\n            rect.x = 0;\n            GUI.Box(rect, \"\");\n\n            drawLeftLine(rect.y, rect.y + 24, HierarchySettings.getInstance().yellowColor);\n\n            rect.x = HierarchySettings.getInstance().lastRect.x + 8;\n            rect.y += 4;\n            EditorGUI.LabelField(rect, title);\n        }\n\n        private static void drawSeparator(int spaceBefore = 0, int spaceAfter = 0, int height = 1)\n        {\n            if (spaceBefore > 0) drawSpace(spaceBefore);\n            Rect rect = getControlRect(0, height, 0, 0);\n            rect.width += 8;\n            EditorGUI.DrawRect(rect, HierarchySettings.getInstance().separatorColor);\n            if (spaceAfter > 0) drawSpace(spaceAfter);\n        }\n\n        private static bool drawComponentCheckBox(string label, HierarchySetting setting)\n        {\n            HierarchySettings.getInstance().indentLevel += 8;\n\n            Rect rect = getControlRect(0, 28, 0, 0);\n\n            float rectWidth = rect.width;\n            bool isChecked = HierarchySettings.getInstance().get<bool>(setting);\n\n            rect.x -= 1;\n            rect.y += 7;\n            rect.width = 14;\n            rect.height = 14;\n\n            if (GUI.Button(rect,\n                    isChecked\n                        ? HierarchySettings.getInstance().checkBoxChecked\n                        : HierarchySettings.getInstance().checkBoxUnchecked,\n                    GUIStyle.none))\n            {\n                HierarchySettings.getInstance().set(setting, !isChecked);\n            }\n\n            rect.x += 14 + 10;\n            rect.width = rectWidth - 14 - 8;\n            rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n            rect.height = EditorGUIUtility.singleLineHeight;\n\n            EditorGUI.LabelField(rect, label);\n\n            HierarchySettings.getInstance().indentLevel -= 8;\n\n            return isChecked;\n        }\n\n        private static bool drawCheckBoxRight(string label, HierarchySetting setting)\n        {\n            Rect rect = getControlRect(0, 18, 34, 6);\n            bool result = false;\n            bool isChecked = HierarchySettings.getInstance().get<bool>(setting);\n\n            float tempX = rect.x;\n            rect.x += rect.width - 14;\n            rect.y += 1;\n            rect.width = 14;\n            rect.height = 14;\n\n            if (GUI.Button(rect,\n                    isChecked\n                        ? HierarchySettings.getInstance().checkBoxChecked\n                        : HierarchySettings.getInstance().checkBoxUnchecked,\n                    GUIStyle.none))\n            {\n                HierarchySettings.getInstance().set(setting, !isChecked);\n                result = true;\n            }\n\n            rect.width = rect.x - tempX - 4;\n            rect.x = tempX;\n            rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n            rect.height = EditorGUIUtility.singleLineHeight;\n\n            EditorGUI.LabelField(rect, label);\n\n            return result;\n        }\n\n        private static void drawSpace(int value)\n        {\n            getControlRect(0, value, 0, 0);\n        }\n\n        private static void drawBackground(float x, float y, float width, float height)\n        {\n            EditorGUI.DrawRect(new Rect(x, y, width, height), HierarchySettings.getInstance().separatorColor);\n        }\n\n        private static void drawLeftLine(float fromY, float toY, Color color, float width = 0)\n        {\n            EditorGUI.DrawRect(\n                new Rect(0, fromY, width == 0 ? HierarchySettings.getInstance().indentLevel : width, toY - fromY),\n                color);\n        }\n\n        private static Rect getControlRect(float width, float height, float addIndent = 0,\n            float remWidth = 0)\n        {\n            EditorGUILayout.GetControlRect(false, height, GUIStyle.none,\n                GUILayout.ExpandWidth(true));\n            Rect rect = new Rect(HierarchySettings.getInstance().indentLevel + addIndent,\n                HierarchySettings.getInstance().lastRect.y + HierarchySettings.getInstance().lastRect.height,\n                (width == 0\n                    ? HierarchySettings.getInstance().totalWidth - HierarchySettings.getInstance().indentLevel -\n                      addIndent - remWidth\n                    : width), height);\n            HierarchySettings.getInstance().lastRect = rect;\n            return rect;\n        }\n\n        private static bool drawRestore()\n        {\n            if (GUI.Button(\n                    new Rect(\n                        HierarchySettings.getInstance().lastRect.x + HierarchySettings.getInstance().lastRect.width -\n                        16 - 5,\n                        HierarchySettings.getInstance().lastRect.y - 20, 16, 16),\n                    HierarchySettings.getInstance().restoreButtonTexture, GUIStyle.none))\n            {\n                if (EditorUtility.DisplayDialog(\"Restore\", \"Restore default settings?\", \"Ok\",\n                        \"Cancel\"))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        // GUI COMPONENTS\n        private static void drawLabel(string label)\n        {\n            Rect rect = getControlRect(0, 16, 34, 6);\n            rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n            EditorGUI.LabelField(rect, label);\n            drawSpace(2);\n        }\n\n        private static void drawTextField(string label, HierarchySetting setting)\n        {\n            string currentValue = HierarchySettings.getInstance().get<string>(setting);\n            string newValue =\n                EditorGUI.TextField(getControlRect(0, 16, 34, 6), label, currentValue);\n            if (!currentValue.Equals(newValue)) HierarchySettings.getInstance().set(setting, newValue);\n            drawSpace(2);\n        }\n\n        private static bool drawFoldout(string label, HierarchySetting setting)\n        {\n#if UNITY_2019_1_OR_NEWER\n            Rect foldoutRect = getControlRect(0, 16, 19, 6);\n#else\n                Rect foldoutRect = getControlRect(0, 16, 22, 6);\n#endif\n            bool foldoutValue = HierarchySettings.getInstance().get<bool>(setting);\n            bool newFoldoutValue = EditorGUI.Foldout(foldoutRect, foldoutValue, label);\n            if (foldoutValue != newFoldoutValue)\n                HierarchySettings.getInstance().set(setting, newFoldoutValue);\n            drawSpace(2);\n            return newFoldoutValue;\n        }\n\n        private static void drawColorPicker(string label, HierarchySetting setting)\n        {\n            Color currentColor = HierarchySettings.getInstance().getColor(setting);\n            Color newColor =\n                EditorGUI.ColorField(getControlRect(0, 16, 34, 6), label, currentColor);\n            if (!currentColor.Equals(newColor)) HierarchySettings.getInstance().setColor(setting, newColor);\n            drawSpace(2);\n        }\n\n        private static Enum drawEnum(string label, HierarchySetting setting, Type enumType)\n        {\n            Enum currentEnum =\n                (Enum)Enum.ToObject(enumType, HierarchySettings.getInstance().get<int>(setting));\n            Enum newEnumValue;\n            if (!(newEnumValue =\n                    EditorGUI.EnumPopup(getControlRect(0, 16, 34, 6), label, currentEnum))\n                .Equals(currentEnum))\n                HierarchySettings.getInstance().set(setting, (int)(object)newEnumValue);\n            drawSpace(2);\n            return newEnumValue;\n        }\n\n        private static void drawIntSlider(string label, HierarchySetting setting, int minValue, int maxValue)\n        {\n            Rect rect = getControlRect(0, 16, 34, 4);\n            int currentValue = HierarchySettings.getInstance().get<int>(setting);\n            int newValue = EditorGUI.IntSlider(rect, label, currentValue, minValue, maxValue);\n            if (currentValue != newValue) HierarchySettings.getInstance().set(setting, newValue);\n            drawSpace(2);\n        }\n\n        private static void drawFloatSlider(string label, HierarchySetting setting, float minValue, float maxValue)\n        {\n            Rect rect = getControlRect(0, 16, 34, 4);\n            float currentValue = HierarchySettings.getInstance().get<float>(setting);\n            float newValue = EditorGUI.Slider(rect, label, currentValue, minValue, maxValue);\n            if (currentValue != newValue) HierarchySettings.getInstance().set(setting, newValue);\n            drawSpace(2);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPHierarchyDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: fa1ae88aaebf4b16a758d736c4b85d81\ntimeCreated: 1705920622"
  },
  {
    "path": "VirtueSky/ControlPanel/CPIapDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\n#if VIRTUESKY_IAP\nusing VirtueSky.Iap;\n#endif\n\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPIapDrawer\n    {\n#if VIRTUESKY_IAP\n        private static IapSetting _iapSetting;\n#endif\n        private static UnityEditor.Editor _editor;\n        private static Vector2 scroll = Vector2.zero;\n\n        public static void OnEnable()\n        {\n            Init();\n        }\n\n        private static void Init()\n        {\n            if (_editor != null)\n            {\n                _editor = null;\n            }\n#if VIRTUESKY_IAP\n            _iapSetting = CreateAsset.GetScriptableAsset<VirtueSky.Iap.IapSetting>();\n            _editor = UnityEditor.Editor.CreateEditor(_iapSetting);\n#endif\n        }\n\n        public static void OnDrawIap(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.InAppPurchase, \"In App Purchase\");\n            GUILayout.Space(10);\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n#if VIRTUESKY_IAP\n            if (_iapSetting == null)\n            {\n                if (GUILayout.Button(\"Create IAP Setting\"))\n                {\n                    _iapSetting =\n                        CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Iap.IapSetting>(\"/Iap/Setting\",\n                            isPingAsset: false);\n                    Init();\n                }\n            }\n            else\n            {\n                if (_editor == null)\n                {\n                    EditorGUILayout.HelpBox(\"Couldn't create the settings resources editor.\",\n                        MessageType.Error);\n                    return;\n                }\n                else\n                {\n                    _editor.OnInspectorGUI();\n                }\n            }\n#else\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols \\\"{ConstantDefineSymbols.VIRTUESKY_IAP}\\\" to use IAP\",\n                MessageType.Warning);\n#endif\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Install Sdk\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonInstallPackage(\"Install In App Purchasing\", \"Remove In App Purchasing\",\n                ConstantPackage.PackageNameInAppPurchase, ConstantPackage.MaxVersionInAppPurchase);\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define Symbols\");\n            GUILayout.Space(10);\n\n#if !VIRTUESKY_IAP\n            EditorGUILayout.HelpBox(\n                    $\"Add scripting define symbols \\\"{ConstantDefineSymbols.VIRTUESKY_IAP}\\\" to use IAP\",\n                    MessageType.Info);\n#endif\n\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_IAP);\n#if VIRTUESKY_IAP\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            GUILayout.Label(\"Ping Iap Settings\", EditorStyles.boldLabel);\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Ping\"))\n            {\n                if (_iapSetting == null)\n                {\n                    Debug.LogError(\"IapSetting have not been created yet\");\n                }\n                else\n                {\n                    EditorGUIUtility.PingObject(_iapSetting);\n                    Selection.activeObject = _iapSetting;\n                }\n            }\n#endif\n            GUILayout.Space(10);\n            EditorGUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPIapDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 70419656f8c04e408772abf5d2e24ad2\ntimeCreated: 1704943160"
  },
  {
    "path": "VirtueSky/ControlPanel/CPInAppReviewDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Misc;\nusing VirtueSky.Rating;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPInAppReviewDrawer\n    {\n        public static void OnDrawInAppReview(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.InAppReview, \"In App Review\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Create Scriptable In App Review\"))\n            {\n                RatingWindowEditor.CreateInAppReview();\n            }\n\n            GUILayout.Space(10);\n            CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Install Sdk\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonInstallPackage(\"Install Google Play Review\", \"Remove Google Play Review\",\n                ConstantPackage.PackageNameGGPlayReview, ConstantPackage.MaxVersionGGPlayReview);\n            CPUtility.DrawButtonInstallPackage(\"Install Google Play Core\", \"Remove Google Play Core\",\n                ConstantPackage.PackageNameGGPlayCore, ConstantPackage.MaxVersionGGPlayCore);\n            CPUtility.DrawButtonInstallPackage(\"Install Google Play Common\", \"Remove Google Play Common\",\n                ConstantPackage.PackageNameGGPlayCommon, ConstantPackage.MaxVersionGGPlayCommon);\n            CPUtility.DrawButtonInstallPackage(\"Install Google External Dependency Manager\",\n                \"Remove Google External Dependency Manager\",\n                ConstantPackage.PackageNameGGExternalDependencyManager,\n                ConstantPackage.MaxVersionGGExternalDependencyManager);\n\n            GUILayout.Space(10);\n            CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define symbols\");\n            GUILayout.Space(10);\n#if !VIRTUESKY_RATING\n            EditorGUILayout.HelpBox(\n                \"Add scripting define symbols \\\"VIRTUESKY_RATING\\\" to use In App Review\",\n                MessageType.Info);\n#endif\n\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_RATING);\n\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPInAppReviewDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5f12bee3b37b49d2b42c61c57f79c05e\ntimeCreated: 1704943618"
  },
  {
    "path": "VirtueSky/ControlPanel/CPLevelEditorDrawer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEditor.SceneManagement;\nusing UnityEngine;\nusing VirtueSky.LevelEditor;\nusing VirtueSky.Misc;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPLevelEditorDrawer\n    {\n        private static LevelEditorTabType levelEditorTabType = LevelEditorTabType.Setting;\n\n        public static void OnDrawLevelEditor(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.LevelEditor, \"Level Editor\");\n            GUILayout.Space(10);\n            var scriptableSetting = Resources.Load<LevelSystemEditorSetting>(nameof(LevelSystemEditorSetting));\n            if (scriptableSetting == null)\n            {\n                GUI.enabled = !EditorApplication.isCompiling;\n                if (GUILayout.Button(\"Setup Level Editor\"))\n                {\n                    var setting = ScriptableObject.CreateInstance<LevelSystemEditorSetting>();\n                    const string path = \"Assets/_Sunflower/Editor/Resources\";\n                    if (!Directory.Exists(path)) Directory.CreateDirectory(path);\n                    AssetDatabase.CreateAsset(setting, $\"{path}/{nameof(LevelSystemEditorSetting)}.asset\");\n                    RegistryManager.Add(\"com.unity.addressables\", \"1.21.21\");\n                    RegistryManager.Resolve();\n                    AssetDatabase.SaveAssets();\n                    AssetDatabase.Refresh();\n                    Debug.Log(\n                        $\"{nameof(LevelSystemEditorSetting)} was created ad {path}/{nameof(LevelSystemEditorSetting)}.asset\");\n                }\n\n                GUI.enabled = true;\n            }\n            else\n            {\n                if (scriptableSetting.PickObjects.Count == 0) RefreshAll();\n                DrawTab();\n                GUILayout.Space(10);\n                CPUtility.GuiLine(2);\n                GUILayout.Space(10);\n                DrawContent(position);\n            }\n\n            GUILayout.EndVertical();\n        }\n\n        static void DrawTab()\n        {\n            EditorGUILayout.BeginHorizontal();\n            bool clickSetting = GUILayout.Toggle(levelEditorTabType == LevelEditorTabType.Setting, \"Setting\",\n                GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25));\n            if (clickSetting && levelEditorTabType != LevelEditorTabType.Setting)\n            {\n                levelEditorTabType = LevelEditorTabType.Setting;\n            }\n\n            bool clickPickup = GUILayout.Toggle(levelEditorTabType == LevelEditorTabType.Pickup, \"Pickup Area\",\n                GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25));\n            if (clickPickup && levelEditorTabType != LevelEditorTabType.Pickup)\n            {\n                levelEditorTabType = LevelEditorTabType.Pickup;\n                RefreshAll();\n            }\n\n            EditorGUILayout.EndHorizontal();\n        }\n\n        #region preview generator\n\n        private static PreviewGenerator previewGenerator;\n\n        private static PreviewGenerator PreviewGenerator\n        {\n            get\n            {\n                var generator = previewGenerator;\n                if (generator != null) return generator;\n\n                return previewGenerator = new PreviewGenerator\n                {\n                    width = 512, height = 512, transparentBackground = true,\n                    sizingType = PreviewGenerator.ImageSizeType.Fit\n                };\n            }\n        }\n\n        private static Dictionary<GameObject, Texture2D> previewDict;\n\n        public static void ClearPreviews()\n        {\n            if (previewDict != null)\n            {\n                foreach (var kvp in previewDict.ToList())\n                {\n                    previewDict[kvp.Key] = null;\n                }\n\n                previewDict.Clear();\n            }\n        }\n\n        public static void ClearPreview(GameObject go)\n        {\n            if (previewDict != null)\n            {\n                foreach (var kvp in previewDict.ToList())\n                {\n                    previewDict[kvp.Key] = null;\n                }\n\n                previewDict.Clear();\n            }\n        }\n\n        public static Texture2D GetPreview(GameObject go, bool canCreate = true)\n        {\n            if (!go) return null;\n            previewDict ??= new Dictionary<GameObject, Texture2D>();\n            previewDict.TryGetValue(go, out var tex);\n            if (!canCreate) return tex != null ? tex : default;\n\n            if (tex) return tex;\n            tex = PreviewGenerator.CreatePreview(go.gameObject);\n            previewDict[go] = tex;\n\n            return tex;\n        }\n\n        #endregion\n\n        private static Vector2 EventMousePoint\n        {\n            get\n            {\n                var position = Event.current.mousePosition;\n                position.y = Screen.height - position.y - 60f;\n                return position;\n            }\n        }\n\n        private static List<PickObject> PickObjects =>\n            LevelSystemEditorSetting.Instance.PickObjects ??= new List<PickObject>();\n\n\n        public static void OnEnable()\n        {\n            if (!LevelSystemEditorSetting.IsExist()) return;\n            RefreshPickObject();\n            SceneView.duringSceneGui += OnSceneGUI;\n        }\n\n        public static void OnDisable()\n        {\n            SceneView.duringSceneGui -= OnSceneGUI;\n        }\n\n\n        private static void OnProjectChange()\n        {\n            TryClose();\n        }\n\n        private static void OnHierarchyChange()\n        {\n            TryClose();\n        }\n\n        private static bool TryClose()\n        {\n            return false;\n        }\n\n        // ReSharper disable once UnusedMember.Local\n        private static void RefreshAll()\n        {\n            ClearPreviews();\n            RefreshPickObject();\n            // ClearEditor(window);\n        }\n\n        /// <summary>\n        /// display picked object in editor\n        /// </summary>\n        private static void RefreshPickObject()\n        {\n            LevelSystemEditorSetting.Instance.PickObjects = new List<PickObject>();\n            var blacklistAssets = new List<GameObject>();\n            var whitelistAssets = new List<GameObject>();\n            if (!LevelSystemEditorSetting.Instance.blacklistPaths.IsNullOrEmpty())\n            {\n                blacklistAssets = AssetDatabase.FindAssets(\"t:GameObject\",\n                        LevelSystemEditorSetting.Instance.blacklistPaths.ToArray())\n                    .Select(AssetDatabase.GUIDToAssetPath)\n                    .Select(AssetDatabase.LoadAssetAtPath<GameObject>)\n                    .ToList();\n\n                foreach (string blacklistPath in LevelSystemEditorSetting.Instance.blacklistPaths)\n                {\n                    if (File.Exists(blacklistPath))\n                        blacklistAssets.Add(\n                            AssetDatabase.LoadAssetAtPath<GameObject>(blacklistPath));\n                }\n            }\n\n            if (!LevelSystemEditorSetting.Instance.whitelistPaths.IsNullOrEmpty())\n            {\n                whitelistAssets = AssetDatabase.FindAssets(\"t:GameObject\",\n                        LevelSystemEditorSetting.Instance.whitelistPaths.ToArray())\n                    .Select(AssetDatabase.GUIDToAssetPath)\n                    .Select(AssetDatabase.LoadAssetAtPath<GameObject>)\n                    .ToList();\n\n                foreach (string whitelistPath in LevelSystemEditorSetting.Instance.whitelistPaths)\n                {\n                    if (File.Exists(whitelistPath))\n                        whitelistAssets.Add(\n                            AssetDatabase.LoadAssetAtPath<GameObject>(whitelistPath));\n                }\n            }\n\n            var resultAssets = whitelistAssets.Where(_ => !blacklistAssets.Contains(_));\n            foreach (var o in resultAssets)\n            {\n                string group = Path.GetDirectoryName(AssetDatabase.GetAssetPath(o))\n                    ?.Replace('\\\\', '/').Split('/').Last();\n                var po = new PickObject { pickedObject = o.gameObject, group = group };\n                LevelSystemEditorSetting.Instance.PickObjects.Add(po);\n            }\n        }\n\n        private static bool CheckEscape()\n        {\n            if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)\n            {\n                LevelSystemEditorSetting.Instance.CurrentPickObject = null;\n                // window.Repaint();\n                SceneView.RepaintAll();\n                return true;\n            }\n\n            return false;\n        }\n\n        private static void DrawContent(Rect position)\n        {\n            if (TryClose()) return;\n            if (CheckEscape()) return;\n            SceneView.RepaintAll();\n            if (levelEditorTabType == LevelEditorTabType.Setting)\n            {\n                InternalDrawSettingTab(position);\n            }\n            else\n            {\n                InternalDrawPickupArea(position);\n            }\n        }\n\n        private static void InternalDrawSettingTab(Rect position)\n        {\n            GUILayout.BeginVertical();\n            LevelSystemEditorSetting.Instance.SettingTabScrollPosition =\n                GUILayout.BeginScrollView(LevelSystemEditorSetting.Instance.SettingTabScrollPosition);\n            InternalDrawDropArea(position);\n            GUILayout.Space(4);\n            InternalDrawSetting();\n            GUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n\n        private static void InternalDrawDropArea(Rect position)\n        {\n            Uniform.DrawGroupFoldout(\"level_editor_drop_area\", \"Drop Area\", DrawDropArea);\n\n            void DrawDropArea()\n            {\n                GUILayout.Space(2);\n                float width = 0;\n                var @event = Event.current;\n\n                #region horizontal\n\n                EditorGUILayout.BeginHorizontal();\n                float widthArea = (float)(position.width - ConstantControlPanel.POSITION_X_START_CONTENT) / 2 - 5;\n                var whiteArea = GUILayoutUtility.GetRect(widthArea, 50f, GUILayout.ExpandWidth(true));\n                var blackArea = GUILayoutUtility.GetRect(widthArea, 50f, GUILayout.ExpandWidth(true));\n                // ReSharper disable once CompareOfFloatsByEqualityOperator\n                if (whiteArea.width == 1f) width = widthArea;\n                else width = whiteArea.width;\n                GUI.backgroundColor = new Color(0f, 0.83f, 1f);\n                GUI.Box(whiteArea, \"[WHITE LIST]\",\n                    new GUIStyle(EditorStyles.helpBox)\n                        { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic });\n                GUI.backgroundColor = Color.white;\n                GUI.backgroundColor = new Color(1f, 0.13f, 0f);\n                GUI.Box(blackArea, \"[BLACK LIST]\",\n                    new GUIStyle(EditorStyles.helpBox)\n                        { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic });\n                GUI.backgroundColor = Color.white;\n                switch (@event.type)\n                {\n                    case EventType.DragUpdated:\n                    case EventType.DragPerform:\n                        if (whiteArea.Contains(@event.mousePosition))\n                        {\n                            DragAndDrop.visualMode = DragAndDropVisualMode.Copy;\n                            if (@event.type == EventType.DragPerform)\n                            {\n                                DragAndDrop.AcceptDrag();\n                                foreach (string path in DragAndDrop.paths)\n                                {\n                                    if (File.Exists(path))\n                                    {\n                                        var r = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(\n                                            path);\n                                        if (r.GetType() != typeof(GameObject)) continue;\n                                    }\n\n                                    ValidateWhitelist(path,\n                                        ref LevelSystemEditorSetting.Instance.blacklistPaths);\n                                    AddToWhitelist(path);\n                                }\n\n                                ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance\n                                    .whitelistPaths);\n                                RefreshAll();\n                            }\n                        }\n                        else if (blackArea.Contains(@event.mousePosition))\n                        {\n                            DragAndDrop.visualMode = DragAndDropVisualMode.Copy;\n                            if (@event.type == EventType.DragPerform)\n                            {\n                                DragAndDrop.AcceptDrag();\n                                foreach (string path in DragAndDrop.paths)\n                                {\n                                    if (File.Exists(path))\n                                    {\n                                        var r = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(\n                                            path);\n                                        if (r.GetType() != typeof(GameObject)) continue;\n                                    }\n\n                                    ValidateBlacklist(path,\n                                        ref LevelSystemEditorSetting.Instance.whitelistPaths);\n                                    AddToBlacklist(path);\n                                }\n\n                                ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance\n                                    .blacklistPaths);\n                                RefreshAll();\n                            }\n                        }\n\n                        break;\n                    case EventType.MouseDown when @event.button == 1:\n                        var menu = new GenericMenu();\n                        if (whiteArea.Contains(@event.mousePosition))\n                        {\n                            menu.AddItem(new GUIContent(\"Clear All [WHITE LIST]\"),\n                                false,\n                                () =>\n                                {\n                                    LevelSystemEditorSetting.Instance.whitelistPaths.Clear();\n                                    SaveLevelSystemSetting();\n                                    RefreshAll();\n                                });\n                        }\n                        else if (blackArea.Contains(@event.mousePosition))\n                        {\n                            menu.AddItem(new GUIContent(\"Clear All [BLACK LIST]\"),\n                                false,\n                                () =>\n                                {\n                                    LevelSystemEditorSetting.Instance.blacklistPaths.Clear();\n                                    SaveLevelSystemSetting();\n                                    RefreshAll();\n                                });\n                        }\n\n                        menu.ShowAsContext();\n                        break;\n                }\n\n                EditorGUILayout.EndHorizontal();\n\n                #endregion\n\n\n                #region horizontal\n\n                EditorGUILayout.BeginHorizontal();\n\n                #region vertical scope\n\n                using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 10)))\n                {\n                    if (LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0)\n                    {\n                        EditorGUILayout.LabelField(new GUIContent(\"\"), GUILayout.Width(width - 50),\n                            GUILayout.Height(0));\n                    }\n                    else\n                    {\n                        GUILayout.Space(2);\n                        LevelSystemEditorSetting.Instance.WhitelistScrollPosition = GUILayout.BeginScrollView(\n                            LevelSystemEditorSetting.Instance.WhitelistScrollPosition,\n                            false, false, GUILayout.Height(250));\n                        foreach (string t in LevelSystemEditorSetting.Instance.whitelistPaths\n                                     .ToList())\n                        {\n                            DrawRow(t,\n                                width,\n                                _ =>\n                                {\n                                    LevelSystemEditorSetting.Instance.whitelistPaths.Remove(_);\n                                    SaveLevelSystemSetting();\n                                });\n                        }\n\n                        GUILayout.EndScrollView();\n                    }\n                }\n\n                #endregion\n\n\n                GUILayout.Space(4);\n\n                #region vertical scope\n\n                using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 15)))\n                {\n                    if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0)\n                    {\n                        EditorGUILayout.LabelField(new GUIContent(\"\"), GUILayout.Width(width - 50),\n                            GUILayout.Height(0));\n                    }\n                    else\n                    {\n                        GUILayout.Space(2);\n                        LevelSystemEditorSetting.Instance.BlacklistScrollPosition = GUILayout.BeginScrollView(\n                            LevelSystemEditorSetting.Instance.BlacklistScrollPosition,\n                            false, false, GUILayout.Height(250));\n                        foreach (string t in LevelSystemEditorSetting.Instance.blacklistPaths\n                                     .ToList())\n                        {\n                            DrawRow(t,\n                                width,\n                                _ =>\n                                {\n                                    LevelSystemEditorSetting.Instance.blacklistPaths.Remove(_);\n                                    SaveLevelSystemSetting();\n                                });\n                        }\n\n                        GUILayout.EndScrollView();\n                    }\n                }\n\n                #endregion\n\n\n                EditorGUILayout.EndHorizontal();\n\n                #endregion\n            }\n\n            void DrawRow(string content, float width, Action<string> action)\n            {\n                #region horizontal\n\n                EditorGUILayout.BeginHorizontal();\n                EditorGUILayout.LabelField(new GUIContent(content), GUILayout.Width(width - 100));\n                GUILayout.FlexibleSpace();\n                if (GUILayout.Button(Uniform.IconContent(\"d_scenevis_visible_hover\",\n                        \"Ping Selection\")))\n                {\n                    var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(content);\n                    Selection.activeObject = obj;\n                    EditorGUIUtility.PingObject(obj);\n                }\n\n                if (GUILayout.Button(Uniform.IconContent(\"Toolbar Minus\", \"Remove\")))\n                {\n                    action?.Invoke(content);\n                    RefreshAll();\n                }\n\n                EditorGUILayout.EndHorizontal();\n\n                #endregion\n            }\n        }\n\n        private static void ValidateWhitelist(string path, ref List<string> blackList)\n        {\n            foreach (string t in blackList.ToList())\n            {\n                if (path.Equals(t)) blackList.Remove(t);\n            }\n        }\n\n        private static void ValidateBlacklist(string path, ref List<string> whiteList)\n        {\n            foreach (string t in whiteList.ToList())\n            {\n                if (path.Equals(t) || IsChildOfPath(t, path)) whiteList.Remove(t);\n            }\n        }\n\n        private static void AddToWhitelist(string path)\n        {\n            var check = false;\n            foreach (string whitePath in LevelSystemEditorSetting.Instance.whitelistPaths)\n            {\n                if (IsChildOfPath(path, whitePath)) check = true;\n            }\n\n            if (!check) LevelSystemEditorSetting.Instance.whitelistPaths.Add(path);\n            LevelSystemEditorSetting.Instance.whitelistPaths = LevelSystemEditorSetting.Instance\n                .whitelistPaths.Distinct().ToList(); //unique\n            SaveLevelSystemSetting();\n        }\n\n        private static void AddToBlacklist(string path)\n        {\n            var check = false;\n            foreach (string blackPath in LevelSystemEditorSetting.Instance.blacklistPaths)\n            {\n                if (IsChildOfPath(path, blackPath)) check = true;\n            }\n\n            if (!check) LevelSystemEditorSetting.Instance.blacklistPaths.Add(path);\n            LevelSystemEditorSetting.Instance.blacklistPaths = LevelSystemEditorSetting.Instance\n                .blacklistPaths.Distinct().ToList(); //unique\n            SaveLevelSystemSetting();\n        }\n\n        // return true if child is childrent of parent\n        private static bool IsChildOfPath(string child, string parent)\n        {\n            if (child.Equals(parent)) return false;\n            var allParent = new List<DirectoryInfo>();\n            GetAllParentDirectories(new DirectoryInfo(child), ref allParent);\n\n            foreach (var p in allParent)\n            {\n                bool check = EqualPath(p, parent);\n                if (check) return true;\n            }\n\n            return false;\n        }\n\n        private static void GetAllParentDirectories(DirectoryInfo directoryToScan,\n            ref List<DirectoryInfo> directories)\n        {\n            while (true)\n            {\n                if (directoryToScan == null || directoryToScan.Name == directoryToScan.Root.Name ||\n                    !directoryToScan.FullName.Contains(\"Assets\")) return;\n\n                directories.Add(directoryToScan);\n                directoryToScan = directoryToScan.Parent;\n            }\n        }\n\n        private static bool EqualPath(FileSystemInfo info, string str)\n        {\n            string relativePath = info.FullName;\n            if (relativePath.StartsWith(Application.dataPath.Replace('/', '\\\\')))\n                relativePath = \"Assets\" + relativePath.Substring(Application.dataPath.Length);\n            relativePath = relativePath.Replace('\\\\', '/');\n            return str.Equals(relativePath);\n        }\n\n        private static void ReduceScopeDirectory(ref List<string> source)\n        {\n            var arr = new string[source.Count];\n            source.CopyTo(arr);\n            var valueRemove = new List<string>();\n            var unique = arr.Distinct().ToList();\n            foreach (string u in unique)\n            {\n                var check = false;\n                foreach (string k in unique)\n                {\n                    if (IsChildOfPath(u, k)) check = true;\n                }\n\n                if (check) valueRemove.Add(u);\n            }\n\n            foreach (string i in valueRemove)\n            {\n                unique.Remove(i);\n            }\n\n            source = unique;\n        }\n\n        private static void InternalDrawSetting()\n        {\n            Uniform.DrawGroupFoldout(\"level_editor_config\", \"Setting\", DrawSetting);\n\n            void DrawSetting()\n            {\n                LevelSystemEditorSetting.Instance.SelectedSpawn =\n                    EditorGUILayout.Popup(\"Where Spawn\", LevelSystemEditorSetting.Instance.SelectedSpawn,\n                        LevelSystemEditorSetting.Instance.optionsSpawn);\n                if (EditorGUI.EndChangeCheck())\n                {\n                    switch (LevelSystemEditorSetting.Instance\n                                .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower())\n                    {\n                        case \"default\":\n                            break;\n                        case \"index\":\n                            var currentPrefabState = GetCurrentPrefabStage();\n                            if (currentPrefabState != null)\n                            {\n                                LevelSystemEditorSetting.Instance.RootIndexSpawn = EditorGUILayout.IntField(\n                                    new GUIContent(\"Index spawn\", \"Index from root stage contex\"),\n                                    LevelSystemEditorSetting.Instance.RootIndexSpawn);\n                            }\n                            else\n                            {\n                                EditorGUILayout.HelpBox(\"Index spawn only work in PrefabMode!\",\n                                    MessageType.Warning);\n                            }\n\n                            break;\n                        case \"custom\":\n                            LevelSystemEditorSetting.Instance.RootSpawn = (GameObject)EditorGUILayout.ObjectField(\n                                \"Spawn in GO here -->\", LevelSystemEditorSetting.Instance.RootSpawn,\n                                typeof(GameObject), true);\n                            break;\n                    }\n                }\n\n                LevelSystemEditorSetting.Instance.SelectedMode = EditorGUILayout.Popup(\"Mode\",\n                    LevelSystemEditorSetting.Instance.SelectedMode, LevelSystemEditorSetting.Instance.optionsMode);\n                if (EditorGUI.EndChangeCheck())\n                {\n                    switch (LevelSystemEditorSetting.Instance\n                                .optionsMode[LevelSystemEditorSetting.Instance.SelectedMode].ToLower())\n                    {\n                        case \"renderer\":\n                            EditorGUILayout.HelpBox(\"Based on Renderer detection\",\n                                MessageType.Info);\n                            break;\n                        case \"ignore\":\n                            EditorGUILayout.HelpBox(\n                                \"GameObject will be spawn correcty at raycast location\\nIgnore calculate bound object\",\n                                MessageType.Info);\n                            break;\n                    }\n                }\n            }\n        }\n\n        private static void InternalDrawPickupArea(Rect position)\n        {\n            float height = 0f;\n            Uniform.DrawGroupFoldoutWithRightClick(\"level_editor_pickup_area\", \"Pickup Area\",\n                DrawPickupArea, ShowMenuRefresh);\n\n            void DrawPickupArea()\n            {\n                var tex = GetPreview(LevelSystemEditorSetting.Instance.CurrentPickObject\n                    ?.pickedObject);\n                if (tex)\n                {\n                    string pickObjectName = LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject.name;\n\n                    #region horizontal\n\n                    EditorGUILayout.BeginHorizontal();\n                    GUILayout.Space(position.width / 2 - 50);\n                    if (LevelSystemEditorSetting.Instance.EditorInspectorPreview == null ||\n                        LevelSystemEditorSetting.Instance.PreviousObjectInspectorPreview !=\n                        LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject)\n                    {\n                        LevelSystemEditorSetting.Instance.EditorInspectorPreview =\n                            UnityEditor.Editor.CreateEditor(LevelSystemEditorSetting.Instance.CurrentPickObject\n                                ?.pickedObject);\n                    }\n\n                    var rect = GUILayoutUtility.GetLastRect();\n                    LevelSystemEditorSetting.Instance.EditorInspectorPreview.DrawPreview(new Rect(\n                        new Vector2(position.width / 2 - 50, rect.position.y),\n                        new Vector2(100, 100)));\n                    LevelSystemEditorSetting.Instance.PreviousObjectInspectorPreview =\n                        LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject;\n                    GUI.color = new Color(1, 1, 1, 0f);\n                    if (GUILayout.Button(tex, GUILayout.Height(80), GUILayout.Width(80)))\n                    {\n                    }\n\n                    GUI.color = Color.white;\n                    EditorGUILayout.EndHorizontal();\n\n                    #endregion\n\n\n                    EditorGUILayout.LabelField(\n                        $\"Selected: <color=#80D2FF>{pickObjectName}</color>\\nPress Icon Again Or Escape Key To Deselect\",\n                        new GUIStyle(EditorStyles.label) { richText = true },\n                        GUILayout.Height(40));\n                    height -= 128;\n                    EditorGUILayout.HelpBox(\"Shift + Click To Add\", MessageType.Info);\n                }\n                else\n                {\n                    EditorGUILayout.HelpBox(\"Select An Object First\", MessageType.Info);\n                }\n\n                height -= 100;\n                if (Uniform.GetFoldoutState(\"level_editor_drop_area\"))\n                {\n                    if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0 &&\n                        LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0)\n                    {\n                        height -= 94;\n                    }\n                    else\n                    {\n                        // height -= 342;\n                    }\n                }\n                else\n                {\n                    height -= 33;\n                }\n\n                if (Uniform.GetFoldoutState(\"level_editor_config\"))\n                {\n                    switch (LevelSystemEditorSetting.Instance\n                                .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower())\n                    {\n                        case \"default\":\n                            height -= 122;\n                            break;\n                        case \"index\":\n                            var currentPrefabState = GetCurrentPrefabStage();\n                            if (currentPrefabState != null)\n                            {\n                                height -= 146;\n                            }\n                            else\n                            {\n                                height -= 162;\n                            }\n\n                            break;\n                        case \"custom\":\n                            height -= 146;\n                            break;\n                    }\n                }\n                else\n                {\n                    height -= 33;\n                }\n\n                var h = position.height + height;\n                LevelSystemEditorSetting.Instance.PickObjectScrollPosition =\n                    GUILayout.BeginScrollView(LevelSystemEditorSetting.Instance.PickObjectScrollPosition,\n                        GUILayout.Height(h));\n                var resultSplitGroupObjects =\n                    PickObjects.GroupBy(_ => _.group).Select(_ => _.ToList()).ToList();\n                foreach (var splitGroupObject in resultSplitGroupObjects)\n                {\n                    string nameGroup = splitGroupObject[0].group.ToUpper();\n                    Uniform.DrawGroupFoldout($\"level_editor_pickup_area_child_{nameGroup}\",\n                        nameGroup, () => DrawInGroup(splitGroupObject, position));\n                }\n\n                GUILayout.EndScrollView();\n            }\n\n            void DrawInGroup(IReadOnlyList<PickObject> pickObjectsInGroup, Rect position)\n            {\n                const int spacing = 25;\n                var counter = 0;\n                CalculateIdealCount(position.width - 50,\n                    60,\n                    135,\n                    spacing,\n                    5,\n                    out int count,\n                    out float size);\n                count = Mathf.Max(1, count);\n                while (counter >= 0 && counter < pickObjectsInGroup.Count)\n                {\n                    EditorGUILayout.BeginHorizontal();\n                    GUILayout.Space(8);\n                    for (var x = 0; x < count; x++)\n                    {\n                        var pickObj = pickObjectsInGroup[counter];\n                        var go = pickObj.pickedObject;\n                        var tex = GetPreview(go);\n                        if (pickObj == LevelSystemEditorSetting.Instance.CurrentPickObject)\n                        {\n                            GUI.color = new Color32(79, 213, 255, 255);\n                        }\n                        else\n                        {\n                            GUI.color = Color.white;\n                        }\n\n                        if (GUILayout.Button(new GUIContent(\"\"), GUILayout.Width(size),\n                                GUILayout.Height(size)))\n                        {\n                            if (Event.current.button == 1)\n                            {\n                                ShowMenuRightClickItem(pickObj);\n                            }\n                            else\n                            {\n                                LevelSystemEditorSetting.Instance.CurrentPickObject =\n                                    LevelSystemEditorSetting.Instance.CurrentPickObject == pickObj ? null : pickObj;\n                            }\n                        }\n\n                        Rect Grown(Rect r, Vector2 half)\n                        {\n                            return new Rect(r.position - half, r.size + half * 2);\n                        }\n\n                        GUI.color = Color.white;\n                        var rect = GUILayoutUtility.GetLastRect();\n                        if (tex)\n                            GUI.DrawTexture(Grown(rect, Vector2.one * -10), tex,\n                                ScaleMode.ScaleToFit);\n                        if (go)\n                        {\n                            EditorGUI.LabelField(Grown(rect, new Vector2(0, 15)), go.name,\n                                new GUIStyle(EditorStyles.miniLabel)\n                                    { alignment = TextAnchor.LowerCenter, });\n                        }\n\n                        counter++;\n                        if (counter >= pickObjectsInGroup.Count) break;\n                        GUILayout.Space(4);\n                    }\n\n                    GUILayout.FlexibleSpace();\n                    EditorGUILayout.EndHorizontal();\n                    GUILayout.Space(spacing);\n                }\n            }\n\n            void ShowMenuRefresh()\n            {\n                var menu = new GenericMenu();\n                menu.AddItem(new GUIContent(\"Refresh Pickup  Area\"),\n                    false,\n                    () =>\n                    {\n                        LevelSystemEditorSetting.Instance.CurrentPickObject = null;\n                        RefreshAll();\n                    });\n                menu.ShowAsContext();\n            }\n\n            void ShowMenuRightClickItem(PickObject pickObj)\n            {\n                var menu = new GenericMenu();\n                menu.AddItem(new GUIContent(\"Ignore\"), false, () => IgnorePath(pickObj));\n                menu.AddItem(new GUIContent(\"Ping\"),\n                    false,\n                    () =>\n                    {\n                        Selection.activeObject = pickObj.pickedObject;\n                        EditorGUIUtility.PingObject(pickObj.pickedObject);\n                    });\n                menu.ShowAsContext();\n            }\n\n            void IgnorePath(PickObject pickObj)\n            {\n                var path = AssetDatabase.GetAssetPath(pickObj.pickedObject);\n                ValidateBlacklist(path, ref LevelSystemEditorSetting.Instance.whitelistPaths);\n                AddToBlacklist(path);\n                ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance.blacklistPaths);\n                RefreshAll();\n            }\n        }\n\n        private static void SaveLevelSystemSetting()\n        {\n            EditorUtility.SetDirty(LevelSystemEditorSetting.Instance);\n            AssetDatabase.SaveAssets();\n        }\n\n        private static void OnSceneGUI(SceneView sceneView)\n        {\n            if (TryClose()) return;\n            if (CheckEscape()) return;\n            if (LevelSystemEditorSetting.Instance != null)\n            {\n                TryFakeRender(sceneView);\n            }\n        }\n\n        private static void TryFakeRender(SceneView sceneView)\n        {\n            var e = Event.current;\n            if (!e.shift)\n            {\n                if (LevelSystemEditorSetting.Instance.PreviewPickupObject != null)\n                    UnityEngine.Object.DestroyImmediate(LevelSystemEditorSetting.Instance.PreviewPickupObject);\n                return;\n            }\n\n            if (LevelSystemEditorSetting.Instance.CurrentPickObject == null ||\n                !LevelSystemEditorSetting.Instance.CurrentPickObject.pickedObject) return;\n            Vector3 mousePosition;\n            Vector3 normal;\n            if (sceneView.in2DMode)\n            {\n                bool state = EditorExtend.Get2DMouseScenePosition(out var mousePosition2d);\n                mousePosition = mousePosition2d;\n                if (!state) return;\n                EditorExtend.FakeRenderSprite(LevelSystemEditorSetting.Instance.CurrentPickObject.pickedObject,\n                    mousePosition,\n                    Vector3.one, Quaternion.identity);\n                SceneView.RepaintAll();\n\n                if (e.type == EventType.MouseDown && e.button == 0)\n                {\n                    AddPickObject(LevelSystemEditorSetting.Instance.CurrentPickObject, mousePosition);\n                    EditorExtend.SkipEvent();\n                }\n            }\n            else\n            {\n                var pos = EditorExtend.GetInnerGuiPosition(sceneView);\n                RaycastHit? raycastHit;\n                if (pos.Contains(e.mousePosition))\n                {\n                    var currentPrefabState = GetCurrentPrefabStage();\n                    if (currentPrefabState != null)\n                    {\n                        var (mouseCast, hitInfo) = RaycastPoint(GetParent(), EventMousePoint);\n                        mousePosition = mouseCast;\n                        normal = hitInfo.HasValue ? hitInfo.Value.normal : Vector3.up;\n                        raycastHit = hitInfo;\n                    }\n                    else\n                    {\n                        Probe.Pick(ProbeFilter.Default,\n                            sceneView,\n                            e.mousePosition,\n                            out mousePosition,\n                            out normal);\n                        raycastHit = null;\n                    }\n\n                    float discSize = HandleUtility.GetHandleSize(mousePosition) * 0.4f;\n                    Handles.color = new Color(1, 0, 0, 0.5f);\n                    Handles.DrawSolidDisc(mousePosition, normal, discSize * 0.5f);\n\n                    if (!LevelSystemEditorSetting.Instance.PreviewPickupObject)\n                    {\n                        LevelSystemEditorSetting.Instance.PreviewPickupObject =\n                            (GameObject)PrefabUtility.InstantiatePrefab(LevelSystemEditorSetting.Instance\n                                .CurrentPickObject\n                                ?.pickedObject);\n                        StageUtility.PlaceGameObjectInCurrentStage(LevelSystemEditorSetting.Instance\n                            .PreviewPickupObject);\n                        LevelSystemEditorSetting.Instance.PreviewPickupObject.hideFlags = HideFlags.HideAndDontSave;\n                        LevelSystemEditorSetting.Instance.PreviewPickupObject.layer =\n                            LayerMask.NameToLayer(\"Ignore Raycast\");\n                    }\n\n#pragma warning disable CS8321\n                    void SetPosition2()\n                    {\n                        var rendererAttach = LevelSystemEditorSetting.Instance.CurrentPickObject?.pickedObject\n                            .GetComponentInChildren<Renderer>();\n                        if (raycastHit == null || rendererAttach == null) return;\n                        var rendererOther = raycastHit.Value.collider.transform\n                            .GetComponentInChildren<Renderer>();\n                        if (rendererOther == null) return;\n                        LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position = GetSpawnPosition(\n                            rendererAttach,\n                            rendererOther, raycastHit.Value);\n                    }\n#pragma warning restore CS8321\n\n                    void SetPosition()\n                    {\n                        LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position = mousePosition;\n\n                        switch (LevelSystemEditorSetting.Instance\n                                    .optionsMode[LevelSystemEditorSetting.Instance.SelectedMode].ToLower())\n                        {\n                            case \"renderer\":\n                                if (LevelSystemEditorSetting.Instance.PreviewPickupObject.CalculateBounds(\n                                        out var bounds,\n                                        Space.World,\n                                        true,\n                                        false,\n                                        false,\n                                        false))\n                                {\n                                    float difference = 0;\n\n                                    if (normal == Vector3.up || normal == Vector3.down)\n                                    {\n                                        difference = mousePosition.y - bounds.min.y;\n                                    }\n                                    else if (normal == Vector3.right || normal == Vector3.left)\n                                    {\n                                        difference = mousePosition.x - bounds.min.x;\n                                    }\n                                    else if (normal == Vector3.forward || normal == Vector3.back)\n                                    {\n                                        difference = mousePosition.z - bounds.min.z;\n                                    }\n\n                                    LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position +=\n                                        difference * normal;\n                                }\n\n                                break;\n                            case \"ignore\":\n                                break;\n                        }\n                    }\n\n                    SetPosition();\n\n                    if (e.type == EventType.MouseDown && e.button == 0 &&\n                        LevelSystemEditorSetting.Instance.PreviewPickupObject)\n                    {\n                        AddPickObject(LevelSystemEditorSetting.Instance.CurrentPickObject,\n                            LevelSystemEditorSetting.Instance.PreviewPickupObject.transform.position);\n                        EditorExtend.SkipEvent();\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// only use when determined root\n        /// </summary>\n        /// <param name=\"root\"></param>\n        /// <param name=\"ray\"></param>\n        /// <param name=\"point\"></param>\n        /// <returns></returns>\n        private static (bool, RaycastHit?) RayCast(Component root, Ray ray, out Vector3 point)\n        {\n            point = Vector3.zero;\n            if (root.gameObject.scene.GetPhysicsScene()\n                .Raycast(ray.origin, ray.direction, out var hit))\n            {\n                point = hit.point;\n                return (true, hit);\n            }\n\n            return (false, null);\n        }\n\n        /// <summary>\n        /// only use when determined root\n        /// </summary>\n        /// <param name=\"root\"></param>\n        /// <param name=\"screenPoint\"></param>\n        /// <param name=\"distance\"></param>\n        /// <returns></returns>\n        private static (Vector3, RaycastHit?) RaycastPoint(Component root, Vector2 screenPoint,\n            float distance = 20)\n        {\n            var ray = SceneView.currentDrawingSceneView.camera.ScreenPointToRay(screenPoint);\n            var result = RayCast(root, ray, out var point);\n            if (!result.Item1)\n            {\n                point = ray.origin + ray.direction.normalized * distance;\n            }\n\n            return (point, result.Item2);\n        }\n\n        /// <summary>\n        /// for mesh with irregular shape the returned result is incorrect\n        /// missing some direction\n        /// </summary>\n        /// <param name=\"rendererAttach\"></param>\n        /// <param name=\"rendererOther\"></param>\n        /// <param name=\"hitInfo\"></param>\n        /// <returns></returns>\n        private static Vector3 GetSpawnPosition(Renderer rendererAttach, Renderer rendererOther,\n            RaycastHit hitInfo)\n        {\n            var boundsAttach = rendererAttach.bounds;\n            var boundsOther = rendererOther.bounds;\n\n            var otherPos = hitInfo.collider.gameObject.transform.position;\n            var pointPos = hitInfo.point;\n\n            int isSpawnRighSide;\n            if (Mathf.Abs(otherPos.x - pointPos.x) >= boundsOther.size.x / 2)\n            {\n                isSpawnRighSide = otherPos.x > pointPos.x ? -1 : 1;\n            }\n            else\n            {\n                isSpawnRighSide = 0;\n            }\n\n            int isSpawnUpSide;\n            if (Mathf.Abs(otherPos.y - pointPos.y) >= boundsOther.size.y / 2)\n            {\n                isSpawnUpSide = otherPos.y > pointPos.y ? -1 : 1;\n            }\n            else\n            {\n                isSpawnUpSide = 0;\n            }\n\n            int isSpawnForwardSide;\n            if (Mathf.Abs(otherPos.z - pointPos.z) >= boundsOther.size.z / 2)\n            {\n                isSpawnForwardSide = otherPos.z > pointPos.z ? -1 : 1;\n            }\n            else\n            {\n                isSpawnForwardSide = 0;\n            }\n\n            return new Vector3(hitInfo.point.x + (boundsAttach.size.x / 2 * isSpawnRighSide),\n                hitInfo.point.y + (boundsAttach.size.y / 2 * isSpawnUpSide),\n                hitInfo.point.z + (boundsAttach.size.z / 2 * isSpawnForwardSide));\n        }\n\n        /// <summary>\n        /// Spawn pickup object\n        /// </summary>\n        /// <param name=\"pickObject\"></param>\n        /// <param name=\"worldPos\"></param>\n        private static void AddPickObject(PickObject pickObject, Vector3 worldPos)\n        {\n            if (pickObject?.pickedObject)\n            {\n                var inst =\n                    (GameObject)PrefabUtility.InstantiatePrefab(pickObject.pickedObject,\n                        GetParent());\n                inst.transform.position = worldPos;\n                Undo.RegisterCreatedObjectUndo(inst.gameObject, \"Create pick obj\");\n                Selection.activeObject = inst;\n            }\n        }\n\n        private static Transform GetParent()\n        {\n            Transform parent = null;\n            var currentPrefabState = GetCurrentPrefabStage();\n\n            if (currentPrefabState != null)\n            {\n                var prefabRoot = currentPrefabState.prefabContentsRoot.transform;\n                switch (LevelSystemEditorSetting.Instance\n                            .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower())\n                {\n                    case \"default\":\n                        parent = prefabRoot;\n                        break;\n                    case \"index\":\n                        if (LevelSystemEditorSetting.Instance.RootIndexSpawn < 0) parent = prefabRoot;\n                        else if (prefabRoot.childCount - 1 > LevelSystemEditorSetting.Instance.RootIndexSpawn)\n                            parent = prefabRoot.GetChild(LevelSystemEditorSetting.Instance.RootIndexSpawn);\n                        else parent = prefabRoot;\n                        break;\n                    case \"custom\":\n                        parent = LevelSystemEditorSetting.Instance.RootSpawn\n                            ? LevelSystemEditorSetting.Instance.RootSpawn.transform\n                            : prefabRoot;\n                        break;\n                }\n            }\n            else\n            {\n                switch (LevelSystemEditorSetting.Instance\n                            .optionsSpawn[LevelSystemEditorSetting.Instance.SelectedSpawn].ToLower())\n                {\n                    case \"default\":\n                    case \"index\":\n                        parent = null;\n                        break;\n                    case \"custom\":\n                        parent = LevelSystemEditorSetting.Instance.RootSpawn\n                            ? LevelSystemEditorSetting.Instance.RootSpawn.transform\n                            : null;\n                        break;\n                }\n            }\n\n            return parent;\n        }\n\n        private static PrefabStage GetCurrentPrefabStage()\n        {\n            return PrefabStageUtility.GetCurrentPrefabStage();\n        }\n\n        /// <summary>\n        /// Calculate count item pickup can display\n        /// </summary>\n        /// <param name=\"availableSpace\"></param>\n        /// <param name=\"minSize\"></param>\n        /// <param name=\"maxSize\"></param>\n        /// <param name=\"spacing\"></param>\n        /// <param name=\"defaultCount\"></param>\n        /// <param name=\"count\"></param>\n        /// <param name=\"size\"></param>\n        /// <returns></returns>\n        // ReSharper disable once UnusedMethodReturnValue.Local\n        private static bool CalculateIdealCount(float availableSpace, float minSize, float maxSize,\n            float spacing, int defaultCount, out int count, out float size)\n        {\n            float halfSpacing = spacing / 2f;\n            int minCount = Mathf.FloorToInt(availableSpace / (maxSize + halfSpacing));\n            int maxCount = Mathf.FloorToInt(availableSpace / (minSize + halfSpacing));\n            bool goodness = defaultCount >= minCount && defaultCount <= maxCount;\n            count = Mathf.Clamp(defaultCount, minCount, maxCount);\n            size = (availableSpace - halfSpacing * (count - 1) - (count - 1) * (count / 10f)) /\n                   count;\n            return goodness;\n        }\n\n        // private static void ClearEditor(EditorWindow window)\n        // {\n        //     window.Repaint();\n        // }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPLevelEditorDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 804a530dac8b4b5fbee5eedbef28d5ac\ntimeCreated: 1704943685"
  },
  {
    "path": "VirtueSky/ControlPanel/CPLocalizationDrawer.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEngine;\nusing VirtueSky.Localization;\nusing VirtueSky.LocalizationEditor;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPLocalizationDrawer\n    {\n        private static GoogleTranslator Translator => new(LocaleSettings.GoogleTranslateApiKey);\n        private static LocaleTabType localeTabType = LocaleTabType.Setting;\n        private static VirtueSky.Localization.LocaleSettings _settings;\n        private static UnityEditor.Editor _editor;\n        private static Vector2 scroll = Vector2.zero;\n\n        private static LocaleTabType _currentLocaleTab = LocaleTabType.Setting;\n        private static TreeViewState _treeViewState;\n        public static LocaleTreeView _localeTreeView;\n        private static SearchField _localeSearchField;\n        private static float cacheYToolBarRect;\n        private static float cacheWidth;\n        private static bool _localeInitialized;\n        private static MultiColumnHeaderState _multiColumnHeaderState;\n\n        private struct EditorCommands\n        {\n            public const string DUPLICATE = \"Duplicate\";\n            public const string DELETE = \"Delete\";\n            public const string FRAME_SELECTED = \"FrameSelected\";\n        }\n\n        public static void OnEnable()\n        {\n            Init();\n        }\n\n        private static void Init()\n        {\n            if (_editor != null) _editor = null;\n            _settings = CreateAsset.GetScriptableAsset<LocaleSettings>();\n            _editor = UnityEditor.Editor.CreateEditor(_settings);\n        }\n\n        public static void OnDrawLocalization(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.Localization, \"Localization\");\n            GUILayout.Space(10);\n            DrawTab();\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            switch (localeTabType)\n            {\n                case LocaleTabType.Setting:\n                    DrawSetting(position);\n                    break;\n                case LocaleTabType.Explore:\n                    DrawExplore(position);\n                    break;\n            }\n\n            GUILayout.EndVertical();\n        }\n\n        static void DrawTab()\n        {\n            EditorGUILayout.BeginHorizontal();\n            bool clickSetting = GUILayout.Toggle(localeTabType == LocaleTabType.Setting, \"Setting\",\n                GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25));\n            if (clickSetting && localeTabType != LocaleTabType.Setting)\n            {\n                localeTabType = LocaleTabType.Setting;\n            }\n\n            bool clickPickup = GUILayout.Toggle(localeTabType == LocaleTabType.Explore, \"Explore\",\n                GUI.skin.button, GUILayout.ExpandWidth(true), GUILayout.Height(25));\n            if (clickPickup && localeTabType != LocaleTabType.Explore)\n            {\n                localeTabType = LocaleTabType.Explore;\n            }\n\n            EditorGUILayout.EndHorizontal();\n        }\n\n        private static void DrawSetting(Rect position)\n        {\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n            if (_settings == null)\n            {\n                if (GUILayout.Button(\"Create LocaleSettings\"))\n                {\n                    _settings = CreateAsset.CreateAndGetScriptableAsset<LocaleSettings>(\"/Localization/Resources\",\n                        isPingAsset: false);\n                    Init();\n                }\n            }\n            else\n            {\n                if (_editor == null)\n                {\n                    EditorGUILayout.HelpBox(\"Couldn't create the settings editor.\",\n                        MessageType.Error);\n                    return;\n                }\n\n                _editor.OnInspectorGUI();\n                GUILayout.Space(10);\n                CPUtility.GuiLine(2);\n                GUILayout.Space(10);\n                CPUtility.DrawHeader(\"Install Sdk\");\n                GUILayout.Space(10);\n                CPUtility.DrawButtonInstallPackage(\"Install Baking Sheet\", \"Remove Baking Sheet\",\n                    ConstantPackage.PackageNameBakingSheet, ConstantPackage.MaxVersionBakingSheet);\n                GUILayout.Space(10);\n                CPUtility.GuiLine(2);\n                GUILayout.Space(10);\n                CPUtility.DrawHeader(\"Define Symbols\");\n                GUILayout.Space(10);\n                CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_BAKINGSHEET);\n            }\n\n            GUILayout.Space(10);\n            CPUtility.GuiLine(2);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Ping LocaleSettings\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Ping\"))\n            {\n                if (_settings == null)\n                {\n                    Debug.LogError(\"LocaleSettings have not been created yet\");\n                }\n                else\n                {\n                    EditorGUIUtility.PingObject(_settings);\n                    Selection.activeObject = _settings;\n                }\n            }\n\n            GUILayout.Space(10);\n            EditorGUILayout.EndScrollView();\n            GUILayout.Space(10);\n        }\n\n        private static void DrawExplore(Rect position)\n        {\n            cacheYToolBarRect = GUILayoutUtility.GetLastRect().y + 10;\n            cacheWidth = position.width - ConstantControlPanel.POSITION_X_START_CONTENT - 10;\n            Rect ToolbarRect =\n                new(ConstantControlPanel.POSITION_X_START_CONTENT + 5, cacheYToolBarRect, cacheWidth, 5);\n            Rect BottomToolbarRect =\n                new(ConstantControlPanel.POSITION_X_START_CONTENT + 5, position.height - 20, cacheWidth, 20);\n            InitializeIfNeeded(ref _treeViewState, ref _localeTreeView, ref _multiColumnHeaderState,\n                cacheWidth, ref _localeSearchField, ref _localeInitialized);\n            HandleEditorCommands(ref _localeTreeView);\n            SearchBarView(ref _localeTreeView, ref _localeSearchField, ToolbarRect);\n            BottomToolbarView(ref _localeTreeView, BottomToolbarRect);\n            Rect BodyViewRect =\n                new(ConstantControlPanel.POSITION_X_START_CONTENT + 5, cacheYToolBarRect + 20, cacheWidth, position.height - cacheYToolBarRect - 45);\n            BodyView(ref _localeTreeView, BodyViewRect);\n        }\n\n        private static void InitializeIfNeeded(\n            ref TreeViewState treeViewState,\n            ref LocaleTreeView treeView,\n            ref MultiColumnHeaderState multiColumnHeaderState,\n            float bodyViewRectWidth,\n            ref SearchField searchField,\n            ref bool initialized)\n        {\n            if (treeViewState == null || treeView == null || searchField == null) initialized = false;\n\n            if (!initialized)\n            {\n                if (treeViewState == null) treeViewState = new TreeViewState();\n                bool firstInit = multiColumnHeaderState == null;\n                var headerState = LocaleTreeView.CreateDefaultMultiColumnHeaderState(bodyViewRectWidth);\n                if (MultiColumnHeaderState.CanOverwriteSerializedFields(multiColumnHeaderState, headerState))\n                {\n                    MultiColumnHeaderState.OverwriteSerializedFields(multiColumnHeaderState, headerState);\n                }\n\n                multiColumnHeaderState = headerState;\n\n                var multiColumnHeader = new MultiColumnHeader(headerState);\n                if (firstInit) multiColumnHeader.ResizeToFit();\n\n                treeView = new LocaleTreeView(treeViewState, multiColumnHeader);\n                searchField = new SearchField();\n                searchField.downOrUpArrowKeyPressed += treeView.SetFocusAndEnsureSelectedItem;\n\n                initialized = true;\n            }\n        }\n\n        private static void HandleEditorCommands(ref LocaleTreeView treeView)\n        {\n            var selectedItems = GetSelectedAssetItems(ref treeView).ToList();\n            if (selectedItems.Any())\n            {\n                var e = Event.current;\n                if (e.type == EventType.ValidateCommand &&\n                    (e.commandName == EditorCommands.DELETE || e.commandName == EditorCommands.DUPLICATE ||\n                     e.commandName == EditorCommands.FRAME_SELECTED))\n                {\n                    e.Use();\n                }\n\n                if (e.type == EventType.ExecuteCommand)\n                {\n                    switch (e.commandName)\n                    {\n                        case EditorCommands.DELETE:\n                            DeleteAssetItems(selectedItems, ref treeView);\n                            break;\n                        case EditorCommands.DUPLICATE:\n                            DuplicateAssetItems(selectedItems, ref treeView);\n                            break;\n                        case EditorCommands.FRAME_SELECTED:\n                            RevealLocalizedAsset(selectedItems.FirstOrDefault());\n                            break;\n                    }\n                }\n            }\n        }\n\n        private static void DeleteAssetItems(IEnumerable<AssetTreeViewItem> items, ref LocaleTreeView treeView)\n        {\n            foreach (var item in items.ToList())\n            {\n                string assetPath = AssetDatabase.GetAssetPath(item.Asset.GetInstanceID());\n                AssetDatabase.MoveAssetToTrash(assetPath);\n            }\n\n            // refresh view\n            treeView.Reload();\n        }\n\n        private static void DuplicateAssetItems(IEnumerable<AssetTreeViewItem> items, ref LocaleTreeView treeView)\n        {\n            foreach (var item in items)\n            {\n                string assetPath = AssetDatabase.GetAssetPath(item.Asset.GetInstanceID());\n                string newPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);\n                AssetDatabase.CopyAsset(assetPath, newPath);\n            }\n\n            // refresh view\n            treeView.Reload();\n        }\n\n        private static void RevealLocalizedAsset(AssetTreeViewItem assetTreeViewItem)\n        {\n            Debug.Assert(assetTreeViewItem != null);\n            EditorGUIUtility.PingObject(assetTreeViewItem.Asset);\n        }\n\n        private static IEnumerable<AssetTreeViewItem> GetSelectedAssetItems(ref LocaleTreeView treeView)\n        {\n            return GetSelectedItemsAs<AssetTreeViewItem>(ref treeView);\n        }\n\n        private static IEnumerable<T> GetSelectedItemsAs<T>(ref LocaleTreeView treeView) where T : TreeViewItem\n        {\n            if (treeView == null) return Enumerable.Empty<T>();\n            var selection = treeView.GetSelection();\n            var items = treeView.GetRows().Where(item => item as T != null && selection.Contains(item.id));\n            return items.Cast<T>();\n        }\n\n        private static void SearchBarView(ref LocaleTreeView treeView, ref SearchField searchField, Rect rect)\n        {\n            treeView.searchString = searchField.OnGUI(rect, treeView.searchString);\n        }\n\n        private static void BodyView(ref LocaleTreeView treeView, Rect rect)\n        {\n            treeView.OnGUI(rect);\n            OnContextMenu(ref treeView, rect);\n        }\n\n        private static void OnContextMenu(ref LocaleTreeView treeView, Rect rect)\n        {\n            var currentEvent = Event.current;\n            var mousePosition = currentEvent.mousePosition;\n            if (rect.Contains(mousePosition) && currentEvent.type == EventType.ContextClick)\n            {\n                TryGetSelectedTreeViewItem(ref treeView, out var assetTreeViewItem, out var localeTreeViewItem);\n\n                if (assetTreeViewItem != null && localeTreeViewItem != null)\n                {\n                    OnLocaleItemContextMenu(assetTreeViewItem, localeTreeViewItem);\n                    currentEvent.Use();\n                }\n                else\n                {\n                    OnAssetItemContextMenu(ref assetTreeViewItem, ref mousePosition);\n                    currentEvent.Use();\n                }\n            }\n        }\n\n        private static void TryGetSelectedTreeViewItem(ref LocaleTreeView treeView,\n            out AssetTreeViewItem assetTreeViewItem, out LocaleTreeViewItem localeTreeViewItem)\n        {\n            var selectedItem = treeView.GetSelectedItem();\n            assetTreeViewItem = selectedItem as AssetTreeViewItem;\n            localeTreeViewItem = selectedItem as LocaleTreeViewItem;\n\n            if (assetTreeViewItem == null && selectedItem != null)\n            {\n                assetTreeViewItem = ((LocaleTreeViewItem)selectedItem).Parent;\n            }\n        }\n\n        private static void OnAssetItemContextMenu(ref AssetTreeViewItem assetTreeViewItem, ref Vector2 mousePosition)\n        {\n            const string itemCreate = \"Create\";\n            const string itemRename = \"Rename\";\n            const string itemDelete = \"Delete\";\n\n            if (Event.current != null)\n            {\n                mousePosition = Event.current.mousePosition;\n            }\n\n            var menu = new GenericMenu();\n            menu.AddItem(new GUIContent(itemCreate), false, AssetItemContextMenu_Create, mousePosition);\n\n            if (assetTreeViewItem == null)\n            {\n                menu.AddDisabledItem(new GUIContent(itemRename));\n                menu.AddDisabledItem(new GUIContent(itemDelete));\n            }\n            else\n            {\n                menu.AddItem(new GUIContent(itemRename), false, AssetItemContextMenu_Rename);\n                menu.AddItem(new GUIContent(itemDelete), false, AssetItemContextMenu_Delete);\n            }\n\n            menu.ShowAsContext();\n        }\n\n        private static void AssetItemContextMenu_Create(object mousePosition)\n        {\n            CreateLocalizedAssetPopup((Vector2)mousePosition);\n        }\n\n        private static void CreateLocalizedAssetPopup(Vector2 mousePosition)\n        {\n            var popupPosition = new Rect(mousePosition, Vector2.zero);\n            EditorUtility.DisplayPopupMenu(popupPosition, \"Assets/Create/Sunflower/Localization/\", null);\n        }\n\n        private static void AssetItemContextMenu_Rename()\n        {\n            TryGetSelectedTreeViewItem(ref _localeTreeView, out var assetTreeViewItem, out _);\n            RenameLocalizedAsset(ref _localeTreeView, assetTreeViewItem);\n        }\n\n        private static void RenameLocalizedAsset(ref LocaleTreeView treeView, AssetTreeViewItem assetTreeViewItem)\n        {\n            Debug.Assert(assetTreeViewItem != null);\n            treeView.BeginRename(assetTreeViewItem);\n        }\n\n        private static void AssetItemContextMenu_Delete()\n        {\n            DeleteAssetItems(GetSelectedAssetItems(ref _localeTreeView), ref _localeTreeView);\n        }\n\n        private static void OnLocaleItemContextMenu(AssetTreeViewItem assetTreeViewItem,\n            LocaleTreeViewItem localeTreeViewItem)\n        {\n            Debug.Assert(assetTreeViewItem != null);\n            Debug.Assert(localeTreeViewItem != null);\n            var menu = new GenericMenu();\n            menu.AddItem(new GUIContent(\"Make default\"), false, LocaleItemContextMenu_MakeDefault);\n            menu.AddItem(new GUIContent(\"Remove\"), false, LocaleItemContextMenu_Remove);\n            menu.ShowAsContext();\n        }\n\n        private static void LocaleItemContextMenu_MakeDefault()\n        {\n            TryGetSelectedTreeViewItem(ref _localeTreeView, out var assetTreeViewItem, out var localeTreeViewItem);\n            MakeLocaleDefault(ref _localeTreeView, assetTreeViewItem, localeTreeViewItem);\n        }\n\n        private static void LocaleItemContextMenu_Remove()\n        {\n            TryGetSelectedTreeViewItem(ref _localeTreeView, out var assetTreeViewItem, out var localeTreeViewItem);\n            RemoveLocale(ref _localeTreeView, assetTreeViewItem.Asset, localeTreeViewItem.LocaleItem);\n        }\n\n        private static void MakeLocaleDefault(ref LocaleTreeView treeView, AssetTreeViewItem assetTreeViewItem,\n            LocaleTreeViewItem localeTreeViewItem)\n        {\n            var localizedAsset = assetTreeViewItem.Asset;\n            var language = localeTreeViewItem.LocaleItem.Language;\n\n            var serializedObject = new SerializedObject(localizedAsset);\n            serializedObject.Update();\n            var elements = serializedObject.FindProperty(\"items\");\n            if (elements != null && elements.arraySize > 1)\n            {\n                int index = Array.FindIndex(localizedAsset.LocaleItems, x => x.Language == language);\n                if (index >= 0)\n                {\n                    language = new Language(language.Name, language.Code, language.Custom);\n                    elements.MoveArrayElement(index, 0);\n                    serializedObject.ApplyModifiedProperties();\n                    treeView.Reload();\n                    Debug.Log(localizedAsset.name + \":\" + language + \" was set as the default language.\");\n                }\n            }\n        }\n\n        private static void RemoveLocale(ref LocaleTreeView treeView, ScriptableLocaleBase scriptable,\n            LocaleItemBase localeItem)\n        {\n            if (ScriptableLocaleEditor.RemoveLocale(scriptable, localeItem))\n            {\n                treeView.Reload();\n            }\n        }\n\n        private static void BottomToolbarView(ref LocaleTreeView treeView, Rect rect)\n        {\n            var backgroundStyle = new GUIStyle(GUI.skin.box)\n                { normal = { background = CreateTexture(new Color(0.55f, 0.55f, 0.55f, 1f)) } };\n\n            var toolbarStyle = new GUIStyle(EditorStyles.toolbar);\n            var padding = toolbarStyle.padding;\n            padding.left = 0;\n            padding.right = 0;\n            toolbarStyle.padding = padding;\n\n            // Toolbar background.\n            GUI.Box(new Rect(rect.x, rect.y, rect.width, rect.height - 1), GUIContent.none, backgroundStyle);\n\n            // Toolbar itself.\n            GUILayout.BeginArea(new Rect(rect.x, rect.y + 1, rect.width - 1, rect.height));\n            using (new EditorGUILayout.HorizontalScope(toolbarStyle))\n            {\n                TreeViewControls(ref treeView);\n                LocalizedAssetControls(ref treeView);\n                GUILayout.FlexibleSpace();\n                LocaleItemControls(ref treeView);\n            }\n\n            GUILayout.EndArea();\n        }\n\n        public static Texture2D CreateTexture(Color color)\n        {\n            var result = new Texture2D(1, 1, TextureFormat.RGBA32, false);\n            result.SetPixel(0, 0, color);\n            result.Apply();\n            return result;\n        }\n\n        private static void TreeViewControls(ref LocaleTreeView treeView)\n        {\n            if (GUILayout.Button(Uniform.IconContent(\"d_SettingsIcon@2x\", \"Open settings\"), EditorStyles.toolbarButton,\n                    GUILayout.Width(25)))\n            {\n                var settings = LocaleSettings.Instance;\n                if (settings) Selection.activeObject = settings;\n                localeTabType = LocaleTabType.Setting;\n            }\n\n            if (GUILayout.Button(Uniform.IconContent(\"refresh\", \"Refresh the window\"), EditorStyles.toolbarButton))\n            {\n                treeView?.Reload();\n            }\n        }\n\n        private static void LocalizedAssetControls(ref LocaleTreeView treeView)\n        {\n            if (GUILayout.Button(new GUIContent(\"Create\", \"Create a new localized asset.\"),\n                    EditorStyles.toolbarDropDown))\n            {\n                var mousePosition = Event.current.mousePosition;\n                CreateLocalizedAssetPopup(mousePosition);\n            }\n\n            var selectedItem = treeView.GetSelectedItem() as AssetTreeViewItem;\n            GUI.enabled = selectedItem != null;\n            if (GUILayout.Button(new GUIContent(\"Rename\", \"Rename the selected localized asset.\"),\n                    EditorStyles.toolbarButton))\n            {\n                RenameLocalizedAsset(ref treeView, selectedItem);\n            }\n\n            if (GUILayout.Button(new GUIContent(\"Delete\", \"Delete the selected localized asset.\"),\n                    EditorStyles.toolbarButton))\n            {\n                DeleteAssetItems(new[] { selectedItem }, ref treeView);\n            }\n\n            GUI.enabled = true;\n\n            if (GUILayout.Button(new GUIContent(\"Import\", \"Import text from csv file\"), EditorStyles.toolbarButton))\n            {\n                LocaleEditorUtil.Import();\n            }\n\n            if (GUILayout.Button(new GUIContent(\"Export\", \"Export text to csv file\"), EditorStyles.toolbarButton))\n            {\n                LocaleEditorUtil.Export();\n            }\n        }\n\n        private static void LocaleItemControls(ref LocaleTreeView treeView)\n        {\n            TryGetSelectedTreeViewItem(ref treeView, out var assetTreeViewItem, out var localeTreeViewItem);\n\n            GUI.enabled = assetTreeViewItem != null && assetTreeViewItem.Asset.GetGenericType == typeof(string);\n            if (GUILayout.Button(new GUIContent(\"Translate By\", \"Translate missing locales.\"),\n                    EditorStyles.toolbarButton))\n            {\n                TranslateMissingLocalesWithMenu(assetTreeViewItem?.Asset);\n            }\n\n            GUI.enabled = !Application.isPlaying;\n            if (GUILayout.Button(new GUIContent(\"Translate All\", \"Translate all missing locales.\"),\n                    EditorStyles.toolbarButton))\n            {\n                if (EditorUtility.DisplayDialog(\"Translate All\",\n                        \"Are you sure you wish to translate all missing locale?\\nThis action cannot be reversed.\",\n                        \"Yes\", \"No\"))\n                {\n                    Debug.Log(\"[Localization] Starting translate all LocaleText!\");\n                    EditorCoroutine.Start(ExecuteTranslateProcess(treeView));\n                }\n            }\n\n            if (GUILayout.Button(\n                    new GUIContent(\"Fill All LocaleText\",\n                        \"Fill language same with AvaiableLanguage for all LocaleText.\"), EditorStyles.toolbarButton))\n            {\n                if (EditorUtility.DisplayDialog(\"Fill language same AvaiableLanguage for all LocaleText\",\n                        \"Are you sure you wish to fill language same AvaiableLanguage for all LocaleText?\\nThis action cannot be reversed.\",\n                        \"Yes\",\n                        \"No\"))\n                {\n                    EditorCoroutine.Start(ExecuteFillMissingLangProcess(treeView));\n                }\n            }\n\n            // First element is already default.\n            GUI.enabled = Application.isPlaying;\n            if (GUILayout.Button(\n                    new GUIContent(\"App Language\",\n                        Application.isPlaying\n                            ? \"Set application language\"\n                            : \"Application language can be set in play mode\"),\n                    EditorStyles.toolbarButton))\n            {\n                var currentLanguage = Locale.CurrentLanguage;\n                var languages = LocaleSettings.AvailableLanguages;\n\n                var menu = new GenericMenu();\n                foreach (var language in languages)\n                {\n                    menu.AddItem(new GUIContent(language.Name), language == currentLanguage, AppLanguageContextMenu,\n                        language);\n                }\n\n                menu.ShowAsContext();\n            }\n\n            GUI.enabled = assetTreeViewItem != null;\n            if (GUILayout.Button(Uniform.IconContent(\"Toolbar Plus\", \"Add locale for selected asset.\"),\n                    EditorStyles.toolbarButton))\n            {\n                AddLocale(ref treeView, assetTreeViewItem?.Asset);\n            }\n\n            GUI.enabled = localeTreeViewItem != null;\n\n            if (GUILayout.Button(Uniform.IconContent(\"Toolbar Minus\", \"Remove selected locale.\"),\n                    EditorStyles.toolbarButton))\n            {\n                RemoveLocale(ref treeView, assetTreeViewItem?.Asset, localeTreeViewItem?.LocaleItem);\n            }\n\n            GUI.enabled = true;\n\n            IEnumerator ExecuteFillMissingLangProcess(LocaleTreeView treeView)\n            {\n                Debug.Log(\n                    \"[Localization] Starting fill language same with AvaiableLanguage for LocaleText!\"\n                );\n                var rows = treeView.GetRows();\n                foreach (var viewItem in rows.ToList())\n                {\n                    var assetItem = viewItem as AssetTreeViewItem;\n                    FillLanguageSameAvaiableLanguage(assetItem?.Asset);\n                    yield return null;\n                }\n\n                treeView.Reload();\n                Debug.Log(\"[Localization] End fill language all LocaleText!\");\n            }\n\n            IEnumerator ExecuteTranslateProcess(LocaleTreeView treeView)\n            {\n                SessionState.EraseInt(\"translate_all_locale_text_count\");\n                var rows = treeView.GetRows();\n                foreach (var viewItem in rows.ToList())\n                {\n                    var assetItem = viewItem as AssetTreeViewItem;\n                    TranslateMissingLocales(assetItem?.Asset);\n                    yield return new WaitForSeconds(0.15f);\n                }\n\n                Debug.Log(\"[Localization] End translate all LocaleText!\");\n                Debug.Log(\n                    \"Total LocaleText Translated is :\" + SessionState.GetInt(\"translate_all_locale_text_count\", 0));\n                SessionState.EraseInt(\"translate_all_locale_text_count\");\n            }\n        }\n\n        private static void TranslateMissingLocalesWithMenu(ScriptableLocaleBase asset)\n        {\n            var localeText = asset as LocaleText;\n            var options = new List<GUIContent>();\n            if (localeText != null)\n            {\n                Debug.Log(\"[Localization] Starting Translate LocaleText: \" + localeText.name);\n                foreach (var locale in localeText.TypedLocaleItems)\n                {\n                    if (!string.IsNullOrEmpty(locale.Value)) options.Add(new GUIContent(locale.Language.ToString()));\n                }\n\n                var mousePosition = Event.current.mousePosition;\n                var popupPosition = new Rect(mousePosition.x, mousePosition.y, 0, 0);\n                EditorUtility.DisplayCustomMenu(popupPosition,\n                    options.ToArray(),\n                    -1,\n                    TranslateSelected,\n                    localeText);\n            }\n        }\n\n        /// <summary>\n        /// Translate language by first language value\n        /// </summary>\n        /// <param name=\"asset\"></param>\n        private static void TranslateMissingLocales(ScriptableLocaleBase asset)\n        {\n            var localizedText = asset as LocaleText;\n            var options = new List<GUIContent>();\n            if (localizedText != null)\n            {\n                foreach (var locale in localizedText.TypedLocaleItems)\n                {\n                    if (!string.IsNullOrEmpty(locale.Value)) options.Add(new GUIContent(locale.Language.ToString()));\n                }\n\n                TranslateSelected(localizedText, options.Select(c => c.text).ToArray(), 0);\n            }\n        }\n\n        /// <summary>\n        /// Translate language by first language value\n        /// </summary>\n        /// <param name=\"asset\"></param>\n        private static void FillLanguageSameAvaiableLanguage(ScriptableLocaleBase asset)\n        {\n            var localizedText = asset as LocaleText;\n            if (localizedText != null)\n            {\n                foreach (var item in asset.LocaleItems.ToList())\n                {\n                    int index = Array.FindIndex(asset.LocaleItems, x => x.Language == item.Language);\n                    if (!LocaleSettings.AvailableLanguages.Contains(asset.LocaleItems[index].Language))\n                    {\n                        asset.LocaleItems.ToList().RemoveAt(index);\n                    }\n                }\n\n                if (asset.LocaleItems.Length < LocaleSettings.AvailableLanguages.Count)\n                {\n                    foreach (var lang in LocaleSettings.AvailableLanguages)\n                    {\n                        int index = Array.FindIndex(asset.LocaleItems, x => x.Language == lang);\n                        if (index >= 0) continue;\n\n                        ScriptableLocaleEditor.AddLocale(asset);\n                        index = asset.LocaleItems.Length - 1;\n                        var localeItem = asset.LocaleItems[index];\n                        localeItem.Language = lang;\n                        localeItem.ObjectValue = \"\";\n                    }\n                }\n            }\n        }\n\n        private static void TranslateSelected(object userData, string[] options, int selected)\n        {\n            var localizedText = (LocaleText)userData;\n\n            var selectedLanguage = LocaleSettings.AllLanguages.FirstOrDefault(x => x.Name == options[selected]);\n            if (selectedLanguage == null)\n            {\n                Debug.Assert(false, \"Selected language not found in LocaleSettings.AllLanguages.\");\n                return;\n            }\n\n            if (!localizedText.TryGetLocaleValue(selectedLanguage, out string textValue))\n            {\n                Debug.Assert(false, \"Selected language not exist in \" + localizedText.name);\n                return;\n            }\n\n            foreach (var locale in localizedText.TypedLocaleItems)\n            {\n                if (string.IsNullOrEmpty(locale.Value))\n                {\n                    var localeItem = locale;\n                    Translator.Translate(new GoogleTranslateRequest(selectedLanguage, locale.Language, textValue),\n                        e =>\n                        {\n                            var response = e.Responses.FirstOrDefault();\n                            if (response != null)\n                            {\n                                localeItem.Value = response.translatedText;\n                                SessionState.SetInt(\"translate_all_locale_text_count\",\n                                    SessionState.GetInt(\"translate_all_locale_text_count\", 0) + 1);\n                                Debug.Log(\"[Localization] Translate Successfull: \" +\n                                          localizedText.name);\n                            }\n\n                            EditorUtility.SetDirty(localizedText);\n                        },\n                        e => { Debug.LogError(\"Response (\" + e.ResponseCode + \"): \" + e.Message); });\n                }\n            }\n        }\n\n        private static void AppLanguageContextMenu(object language)\n        {\n            Locale.CurrentLanguage = (Language)language;\n        }\n\n        private static void AddLocale(ref LocaleTreeView localeTreeView, ScriptableLocaleBase localizedAsset)\n        {\n            if (ScriptableLocaleEditor.AddLocale(localizedAsset)) localeTreeView.Reload();\n        }\n    }\n\n    public enum LocaleTabType\n    {\n        Setting,\n        Explore\n    }\n\n    /// <summary>\n    /// Refreshes localization tab wizard if is opened.\n    /// </summary>\n    public class ScriptableLocalePostprocessor : AssetPostprocessor\n    {\n        private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)\n        {\n            if (CPLocalizationDrawer._localeTreeView != null) CPLocalizationDrawer._localeTreeView?.Reload();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPLocalizationDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6ff665b53f20434c95bcc686b1bdeffd\ntimeCreated: 1729159142"
  },
  {
    "path": "VirtueSky/ControlPanel/CPNotificationChanelDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPNotificationChanelDrawer\n    {\n        public static void OnDrawNotificationChanel(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.NotificationsChanel, \"Notifications\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Create Notification Chanel\"))\n            {\n                NotificationWindowEditor.CreateNotificationChannel();\n            }\n\n            GUILayout.Space(10);\n            CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Install Sdk\");\n            GUILayout.Space(10);\n            CPUtility.DrawButtonInstallPackage(\"Install Mobile Notifications\", \"Remove Mobile Notifications\",\n                ConstantPackage.PackageNameMobileNotification, ConstantPackage.MaxVersionMobileNotification);\n            GUILayout.Space(10);\n            CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n            GUILayout.Space(10);\n            CPUtility.DrawHeader(\"Define Symbols\");\n            GUILayout.Space(10);\n#if !VIRTUESKY_NOTIFICATION\n            EditorGUILayout.HelpBox(\n                $\"Add scripting define symbols \\\"{ConstantDefineSymbols.VIRTUESKY_NOTIFICATION}\\\" to use IAP\",\n                MessageType.Info);\n#endif\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION);\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPNotificationChanelDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3f51fe616e2e426d8bafbc2de7a103d9\ntimeCreated: 1704943768"
  },
  {
    "path": "VirtueSky/ControlPanel/CPRegisterPackageDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPRegisterPackageDrawer\n    {\n        private static Vector2 scrollPositionFileManifest = Vector2.zero;\n        private static Vector2 scrollPositionAddSomePackage = Vector2.zero;\n\n\n        public static void OnDrawRegisterPackageByManifest(Rect position)\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.RegisterPackage, \"Register Package\");\n            GUILayout.Space(10);\n            scrollPositionAddSomePackage =\n                EditorGUILayout.BeginScrollView(scrollPositionAddSomePackage, GUILayout.Height(150));\n            DrawButtonAddSomePackage();\n            EditorGUILayout.EndScrollView();\n            GUILayout.Space(10);\n            CPUtility.DrawLineLastRectY(3, ConstantControlPanel.POSITION_X_START_CONTENT, position.width);\n            GUILayout.Space(10);\n            GUILayout.Label(\"Manifest.json\", EditorStyles.boldLabel);\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Resolve Package\"))\n            {\n                RegistryManager.Resolve();\n            }\n\n            scrollPositionFileManifest =\n                EditorGUILayout.BeginScrollView(scrollPositionFileManifest,\n                    GUILayout.Height(250));\n            string manifestContent = EditorGUILayout.TextArea(\n                System.IO.File.ReadAllText(FileExtension.ManifestPath),\n                GUILayout.ExpandHeight(true));\n            RegistryManager.WriteAllManifestContent(manifestContent);\n            EditorGUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n\n        static void DrawButtonAddSomePackage()\n        {\n            CPUtility.DrawButtonInstallPackage(\"Install Firebase App\", \"Remove Firebase App\",\n                ConstantPackage.PackageNameFirebaseApp, ConstantPackage.MaxVersionFirebaseApp);\n            CPUtility.DrawButtonInstallPackage(\"Install Firebase Remote Config\", \"Remove Firebase Remote Config\",\n                ConstantPackage.PackageNameFirebaseRemoteConfig, ConstantPackage.MaxVersionFirebaseRemoteConfig);\n            CPUtility.DrawButtonInstallPackage(\"Install Firebase Analytics\", \"Remove Firebase Analytics\",\n                ConstantPackage.PackageNameFirebaseAnalytics, ConstantPackage.MaxVersionFirebaseAnalytics);\n            CPUtility.DrawButtonInstallPackage(\"Install Firebase Crashlytics\", \"Remove Firebase Crashlytics\",\n                ConstantPackage.PackageNameFirebaseCrashlytics, ConstantPackage.MaxVersionFirebaseCrashlytics);\n            CPUtility.DrawButtonInstallPackage(\"Install Firebase Database\", \"Remove Firebase Database\",\n                ConstantPackage.PackageNameFirebaseDatabase, ConstantPackage.MaxVersionFirebaseDatabase);\n            CPUtility.DrawButtonInstallPackage(\"Install Firebase Auth\", \"Remove Firebase Auth\",\n                ConstantPackage.PackageNameFirebaseAuth, ConstantPackage.MaxVersionFirebaseAuth);\n            CPUtility.DrawButtonInstallPackage(\"Install Google External Dependency Manager\",\n                \"Remove Google External Dependency Manager\",\n                ConstantPackage.PackageNameGGExternalDependencyManager,\n                ConstantPackage.MaxVersionGGExternalDependencyManager);\n            CPUtility.DrawButtonInstallPackage(\"Install Adjust\", \"Remove Adjust\",\n                ConstantPackage.PackageNameAdjust, ConstantPackage.MaxVersionAdjust);\n            CPUtility.DrawButtonInstallPackage(\"Install In App Purchasing\", \"Remove In App Purchasing\",\n                ConstantPackage.PackageNameInAppPurchase, ConstantPackage.MaxVersionInAppPurchase);\n            CPUtility.DrawButtonInstallPackage(\"Install AppsFlyer\", \"Remove AppsFlyer\",\n                ConstantPackage.PackageNameAppFlyer, ConstantPackage.MaxVersionAppFlyer);\n            CPUtility.DrawButtonInstallPackage(\"Install Google Play Review\", \"Remove Google Play Review\",\n                ConstantPackage.PackageNameGGPlayReview, ConstantPackage.MaxVersionGGPlayReview);\n            CPUtility.DrawButtonInstallPackage(\"Install Google Play Core\", \"Remove Google Play Core\",\n                ConstantPackage.PackageNameGGPlayCore, ConstantPackage.MaxVersionGGPlayCore);\n            CPUtility.DrawButtonInstallPackage(\"Install Google Play Common\", \"Remove Google Play Common\",\n                ConstantPackage.PackageNameGGPlayCommon, ConstantPackage.MaxVersionGGPlayCommon);\n            CPUtility.DrawButtonInstallPackage(\"Install Newtonsoft.Json\", \"Remove Newtonsoft.Json\",\n                ConstantPackage.PackageNameNewtonsoftJson, ConstantPackage.MaxVersionNewtonsoftJson);\n            CPUtility.DrawButtonInstallPackage(\"Install PlayFab\", \"Remove PlayFab\", ConstantPackage.PackageNamePlayFab,\n                ConstantPackage.MaxVersionPlayFab);\n            CPUtility.DrawButtonInstallPackage(\"Install Coffee UI Effect\", \"Remove Coffee UI Effect\",\n                ConstantPackage.PackageNameCoffeeUIEffect, ConstantPackage.MaxVersionCoffeeUIEffect);\n            CPUtility.DrawButtonInstallPackage(\"Install Coffee UI Particle\", \"Remove Coffee UI Particle\",\n                ConstantPackage.PackageNameCoffeeUIParticle, ConstantPackage.MaxVersionCoffeeUIParticle);\n            CPUtility.DrawButtonInstallPackage(\"Install iOS 14 Advertising Support\",\n                \"Remove iOS 14 Advertising Support\", ConstantPackage.PackageNameIOS14AdvertisingSupport,\n                ConstantPackage.MaxVersionIOS14AdvertisingSupport);\n            CPUtility.DrawButtonInstallPackage(\"Install Spine Csharp\", \"Remove Spine Csharp\",\n                ConstantPackage.PackageNameSpineCsharp, ConstantPackage.MaxVersionSpineCsharp);\n            CPUtility.DrawButtonInstallPackage(\"Install Spine Unity\", \"Remove Spine Unity\",\n                ConstantPackage.PackageNameSpineUnity, ConstantPackage.MaxVersionSpineUnity);\n            CPUtility.DrawButtonInstallPackage(\"Install UniTask\", \"Remove UniTask\", ConstantPackage.PackageNameUniTask,\n                ConstantPackage.MaxVersionUniTask);\n            CPUtility.DrawButtonInstallPackage(\"Install Apple Sign In\", \"Remove Apple Sign In\",\n                ConstantPackage.PackageNameAppleSignIn, ConstantPackage.MaxVersionAppleSignIn);\n            // CPUtility.DrawButtonInstallPackage(\"Install Animancer\", \"Remove Animancer\",\n            //     ConstantPackage.PackageNameAnimancer, ConstantPackage.MaxVersionAnimancer);\n            CPUtility.DrawButtonInstallPackage(\"Install Mobile Notifications\", \"Remove Mobile Notifications\",\n                ConstantPackage.PackageNameMobileNotification, ConstantPackage.MaxVersionMobileNotification);\n            CPUtility.DrawButtonInstallPackage(\"Install Addressables\", \"Remove Addressables\",\n                ConstantPackage.PackageNameAddressables, ConstantPackage.MaxVersionAddressables);\n            CPUtility.DrawButtonInstallPackage(\"Install Baking Sheet\", \"Remove Baking Sheet\",\n                ConstantPackage.PackageNameBakingSheet, ConstantPackage.MaxVersionBakingSheet);\n            CPUtility.DrawButtonInstallPackage(\"Install Admob Sdk Plugin\", \"Remove Admob Sdk Plugin\",\n                ConstantPackage.PackageNameAdmob, ConstantPackage.VersionAdmob);\n            CPUtility.DrawButtonInstallPackage(\"Install LevelPlay Sdk Plugin\", \"Remove LevelPlay Sdk Plugin\",\n                ConstantPackage.PackageNameLevelPlay, ConstantPackage.MaxVersionLevelPlay);\n\n            if (GUILayout.Button(\"Install Google Play Game Service\", GUILayout.Width(400)))\n            {\n                AssetDatabase.ImportPackage(\n                    FileExtension.GetPathFileInCurrentEnvironment(\n                        \"VirtueSky/Utils/Editor/UnityPackage/google-play-game.unitypackage\"), false);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPRegisterPackageDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9fe0737fa3b94df294bf7173df5ca10f\ntimeCreated: 1704943938"
  },
  {
    "path": "VirtueSky/ControlPanel/CPScriptingDefineSymbolsDrawer.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPScriptingDefineSymbolsDrawer\n    {\n        private static Vector2 scroll = Vector2.zero;\n\n        public static void OnDrawScriptingDefineSymbols()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.ScriptDefineSymbols, \"Scripting Define Symbols\");\n            GUILayout.Space(10);\n            scroll = EditorGUILayout.BeginScrollView(scroll);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADS);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLOVIN);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADMOB);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_LEVELPLAY);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ADJUST);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_IAP);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_RATING);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPSFLYER);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.PRIME_TWEEN_SAFETY_CHECKS);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_GPGS);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_SKELETON);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_ANIMANCER);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.UNITASK_ADDRESSABLE_SUPPORT);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.UNITASK_DOTWEEN_SUPPORT);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.UNITASK_TEXTMESHPRO_SUPPORT);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_BAKINGSHEET);\n            CPUtility.DrawButtonAddDefineSymbols(ConstantDefineSymbols.VIRTUESKY_UNITY_SERVICES);\n            EditorGUILayout.EndScrollView();\n            GUILayout.Space(10);\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPScriptingDefineSymbolsDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2086ff90ddc5c6046b461194429b69d2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ControlPanel/CPSoEventDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPSoEventDrawer\n    {\n        static Vector2 scroll = Vector2.zero;\n        private static bool isShowFielEvent = true;\n        private static bool isShowFielEventResult;\n\n        public static void OnDrawSoEvent()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.SO_Event, \"Scriptable Events\");\n            GUILayout.Space(10);\n            scroll = GUILayout.BeginScrollView(scroll);\n            CPUtility.DrawToggle(ref isShowFielEvent, \"Scriptable Event\", DrawButtonEvent);\n            GUILayout.Space(10);\n            CPUtility.DrawToggle(ref isShowFielEventResult, \"Scriptable Event-Result\", DrawButtonEventResult);\n            GUILayout.EndScrollView();\n            GUILayout.EndVertical();\n        }\n\n        static void DrawButtonEvent()\n        {\n            if (GUILayout.Button(\"Create Boolean Event\"))\n            {\n                EventWindowEditor.CreateEventBoolean();\n            }\n\n            if (GUILayout.Button(\"Create Dictionary Event\"))\n            {\n                EventWindowEditor.CreateEventDictionary();\n            }\n\n            if (GUILayout.Button(\"Create No Param Event\"))\n            {\n                EventWindowEditor.CreateEventNoParam();\n            }\n\n            if (GUILayout.Button(\"Create Float Event\"))\n            {\n                EventWindowEditor.CreateEventFloat();\n            }\n\n            if (GUILayout.Button(\"Create Int Event\"))\n            {\n                EventWindowEditor.CreateEventInt();\n            }\n\n            if (GUILayout.Button(\"Create Object Event\"))\n            {\n                EventWindowEditor.CreateEventObject();\n            }\n\n            if (GUILayout.Button(\"Create Short Double Event\"))\n            {\n                EventWindowEditor.CreateEventShortDouble();\n            }\n\n            if (GUILayout.Button(\"Create String Event\"))\n            {\n                EventWindowEditor.CreateEventString();\n            }\n\n            if (GUILayout.Button(\"Create Vector3 Event\"))\n            {\n                EventWindowEditor.CreateEventVector3();\n            }\n\n            if (GUILayout.Button(\"Create Vector2 Event\"))\n            {\n                EventWindowEditor.CreateEventVector2();\n            }\n\n            if (GUILayout.Button(\"Create GameObject Event\"))\n            {\n                EventWindowEditor.CreateEventGameObject();\n            }\n\n            if (GUILayout.Button(\"Create Transform Event\"))\n            {\n                EventWindowEditor.CreateEventTransform();\n            }\n        }\n\n        static void DrawButtonEventResult()\n        {\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_bool_event_result\", \"Bool Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"Bool Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"Bool Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"Bool Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventIntResult();\n                }\n\n                if (GUILayout.Button(\"Bool Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"Bool Event - String Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventStringResult();\n                }\n\n                if (GUILayout.Button(\"Bool Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventVector3Result();\n                }\n\n                if (GUILayout.Button(\"Bool Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Bool Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateBoolEventTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_float_event_result\", \"Float Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"Float Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"Float Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"Float Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventIntResult();\n                }\n\n                if (GUILayout.Button(\"Float Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"Float Event - String Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventStringResult();\n                }\n\n                if (GUILayout.Button(\"Float Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventVector3Result();\n                }\n\n                if (GUILayout.Button(\"Float Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Float Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateFloatEventTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_int_event_result\", \"Int Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"Int Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateIntEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"Int Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateIntEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"Int Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateIntEventIntResult();\n                }\n\n                if (GUILayout.Button(\"Int Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateIntEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"Int Event - String Result\"))\n                {\n                    EventWindowEditor.CreateIntEventStringResult();\n                }\n\n                if (GUILayout.Button(\"Int Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateIntEventVector3Result();\n                }\n\n                if (GUILayout.Button(\"Int Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateIntEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Int Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateIntEventTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_object_event_result\", \"Object Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"Object Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"Object Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"Object Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventIntResult();\n                }\n\n                if (GUILayout.Button(\"Object Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"Object Event - String Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventStringResult();\n                }\n\n                if (GUILayout.Button(\"Object Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventVector3Result();\n                }\n\n                if (GUILayout.Button(\"Object Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Object Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateObjectEventTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_string_event_result\", \"String Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"String Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateStringEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"String Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateStringEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"String Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateStringEventIntResult();\n                }\n\n                if (GUILayout.Button(\"String Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateStringEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"String Event - String Result\"))\n                {\n                    EventWindowEditor.CreateStringEventStringResult();\n                }\n\n                if (GUILayout.Button(\"String Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateStringEventVector3Result();\n                }\n\n                if (GUILayout.Button(\"String Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateStringEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"String Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateStringEventTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_vector3_event_result\", \"Vector3 Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"Vector3 Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventBoolResult();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventFloatResult();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventIntResult();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventObjectResult();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - String Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventStringResult();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventVector3Result();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Vector3 Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateVector3EventTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_event_no_param_result\", \"Event No Param-Result\", () =>\n            {\n                if (GUILayout.Button(\"Event No Param - Bool Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamBoolResult();\n                }\n\n                if (GUILayout.Button(\"Event No Param - Float Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamFloatResult();\n                }\n\n                if (GUILayout.Button(\"Event No Param - Int Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamIntResult();\n                }\n\n                if (GUILayout.Button(\"Event No Param - Object Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamObjectResult();\n                }\n\n                if (GUILayout.Button(\"Event No Param - String Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamStringResult();\n                }\n\n                if (GUILayout.Button(\"Event No Param - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamVector3Result();\n                }\n\n                if (GUILayout.Button(\"Event No Param - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Event No Param - Transform Result\"))\n                {\n                    EventWindowEditor.CreateEventNoParamTransformResult();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_gameobject_event_result\", \"GameObject Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"GameObject Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventIntResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - String Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventStringResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventTransformResult();\n                }\n\n                if (GUILayout.Button(\"GameObject Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateGameObjectEventVector3Result();\n                }\n            }, false);\n            GUILayout.Space(10);\n            Uniform.DrawGroupFoldout(\"cp_draw_transform_event_result\", \"Transform Event-Result\", () =>\n            {\n                if (GUILayout.Button(\"Transform Event - Bool Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventBoolResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - Float Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventFloatResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - GameObject Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventGameObjectResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - Int Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventIntResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - Object Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventObjectResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - String Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventStringResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - Transform Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventTransformResult();\n                }\n\n                if (GUILayout.Button(\"Transform Event - Vector3 Result\"))\n                {\n                    EventWindowEditor.CreateTransformEventVector3Result();\n                }\n            }, false);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPSoEventDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 583e9816b2c1ac148981eb62fc2ee4bb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ControlPanel/CPSoVariableDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public static class CPSoVariableDrawer\n    {\n        public static void OnDrawSoVariable()\n        {\n            GUILayout.Space(10);\n            GUILayout.BeginVertical();\n            CPUtility.DrawHeaderIcon(StatePanelControl.SO_Variable, \"Scriptable Variables\");\n            GUILayout.Space(10);\n            if (GUILayout.Button(\"Create Boolean Variable\"))\n            {\n                VariableWindowEditor.CreateVariableBoolean();\n            }\n\n            if (GUILayout.Button(\"Create Float Variable\"))\n            {\n                VariableWindowEditor.CreateVariableFloat();\n            }\n\n            if (GUILayout.Button(\"Create Int Variable\"))\n            {\n                VariableWindowEditor.CreateVariableInt();\n            }\n\n            if (GUILayout.Button(\"Create Object Variable\"))\n            {\n                VariableWindowEditor.CreateVariableObject();\n            }\n\n            if (GUILayout.Button(\"Create Rect Variable\"))\n            {\n                VariableWindowEditor.CreateVariableRect();\n            }\n\n            if (GUILayout.Button(\"Create Short Double Variable\"))\n            {\n                VariableWindowEditor.CreateVariableShortDouble();\n            }\n\n            if (GUILayout.Button(\"Create String Variable\"))\n            {\n                VariableWindowEditor.CreateVariableString();\n            }\n\n            if (GUILayout.Button(\"Create Transform Variable\"))\n            {\n                VariableWindowEditor.CreateVariableTransform();\n            }\n\n            if (GUILayout.Button(\"Create Vector3 Variable\"))\n            {\n                VariableWindowEditor.CreateVariableVector3();\n            }\n\n            if (GUILayout.Button(\"Create Vector2 Variable\"))\n            {\n                VariableWindowEditor.CreateVariableVector2();\n            }\n\n            GUILayout.EndVertical();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPSoVariableDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1e65b6d553c4a99bcad709550b26740\ntimeCreated: 1704943870"
  },
  {
    "path": "VirtueSky/ControlPanel/CPUtility.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Utils;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class CPUtility\n    {\n        public static void DrawButtonInstallPackage(string labelInstall, string labelRemove,\n            string packageName, string packageVersion, float withButton = 400)\n        {\n            EditorGUILayout.BeginHorizontal();\n            bool isInstall = RegistryManager.IsInstalledPackage(packageName);\n            if (isInstall)\n            {\n                GUI.backgroundColor = CustomColor.Red.ToColor();\n                if (GUILayout.Button(labelRemove, GUILayout.Width(withButton)))\n                {\n                    RegistryManager.Remove(packageName);\n                    RegistryManager.Resolve();\n                }\n            }\n            else\n            {\n                GUI.backgroundColor = CustomColor.Green.ToColor();\n                if (GUILayout.Button(labelInstall, GUILayout.Width(withButton)))\n                {\n                    RegistryManager.AddOverrideVersion(packageName,\n                        packageVersion);\n                }\n            }\n\n            GUI.backgroundColor = Color.white;\n\n            GUILayout.Space(10);\n            GUILayout.Toggle(isInstall, TextIsInstallPackage(isInstall));\n            EditorGUILayout.EndHorizontal();\n        }\n\n        public static void DrawButtonAddDefineSymbols(string flagSymbols, float withButton = 400)\n        {\n            GUILayout.BeginHorizontal();\n            bool isAddSymbols = EditorScriptDefineSymbols.IsFlagEnabled(flagSymbols);\n            string labelButton = isAddSymbols ? \"Remove ---> \" : \"Add ---> \";\n            if (isAddSymbols)\n            {\n                GUI.backgroundColor = CustomColor.Red.ToColor();\n            }\n            else\n            {\n                GUI.backgroundColor = CustomColor.Green.ToColor();\n            }\n\n            if (GUILayout.Button(labelButton + flagSymbols, GUILayout.Width(withButton)))\n            {\n                EditorScriptDefineSymbols.SwitchFlag(flagSymbols);\n            }\n\n            GUI.backgroundColor = Color.white;\n\n            GUILayout.Space(10);\n            GUILayout.Toggle(isAddSymbols, TextIsEnable(isAddSymbols));\n            GUILayout.EndHorizontal();\n        }\n\n        public static string TextIsInstallPackage(bool isInstall)\n        {\n            return isInstall ? \"Installed\" : \"Not installed\";\n        }\n\n        public static string TextIsEnable(bool condition)\n        {\n            return condition ? \"Enable\" : \"Disable\";\n        }\n\n        public static void GuiLine(int i_height = 1, CustomColor customColor = CustomColor.Black)\n        {\n            Rect rect = EditorGUILayout.GetControlRect(false, i_height);\n\n            rect.height = i_height;\n\n            EditorGUI.DrawRect(rect, customColor.ToColor());\n        }\n\n        public static void DrawCustomLine(float with, Vector2 positionPointStart, Vector2 positionPointEnd)\n        {\n            Handles.DrawAAPolyLine(with, positionPointStart, positionPointEnd);\n        }\n\n        public static void DrawLineLastRectY(float with, float posXPointStart, float posXPointEnd, float offsetY = 10)\n        {\n            Handles.DrawAAPolyLine(with, new Vector3(posXPointStart, GUILayoutUtility.GetLastRect().y + offsetY),\n                new Vector3(posXPointEnd, GUILayoutUtility.GetLastRect().y + offsetY));\n        }\n\n        public static void DrawLineLastRectX(float with, float posYPointStart, float posYPointEnd, float offsetX = 10)\n        {\n            Handles.DrawAAPolyLine(with, new Vector3(GUILayoutUtility.GetLastRect().x + offsetX, posYPointStart),\n                new Vector3(GUILayoutUtility.GetLastRect().x + offsetX, posYPointEnd));\n        }\n\n        public static void DrawToggle(ref bool value, string text, System.Action draw)\n        {\n            value = GUILayout.Toggle(value, text);\n            if (value)\n            {\n                draw?.Invoke();\n            }\n        }\n\n        public static Texture2D GetIcon(StatePanelControl statePanelControl)\n        {\n            return statePanelControl switch\n            {\n                StatePanelControl.Advertising => EditorResources.IconAds,\n                StatePanelControl.InAppPurchase => EditorResources.IconIap,\n                StatePanelControl.Audio => EditorResources.IconAudio,\n                StatePanelControl.InAppReview => EditorResources.IconInAppReview,\n                StatePanelControl.NotificationsChanel => EditorResources.IconPushNotification,\n                StatePanelControl.SO_Event => EditorResources.IconScriptableEvent,\n                StatePanelControl.SO_Variable => EditorResources.IconScriptableVariable,\n                StatePanelControl.Adjust => EditorResources.IconAdjust,\n                StatePanelControl.AppsFlyer => EditorResources.IconAppsFlyer,\n                StatePanelControl.GameService => EditorResources.IconGameService,\n                StatePanelControl.Firebase => EditorResources.IconFirebase,\n                StatePanelControl.Hierarchy => EditorResources.IconHierarchy,\n                StatePanelControl.Extensions => EditorResources.IconExtension,\n                StatePanelControl.FolderIcon => EditorResources.IconFolder,\n                StatePanelControl.RegisterPackage => EditorResources.IconPackage,\n                StatePanelControl.Localization => EditorResources.IconLocale,\n                StatePanelControl.About => EditorResources.IconAbout,\n                _ => EditorResources.IconUnity\n            };\n        }\n\n        public static void DrawHeaderIcon(StatePanelControl statePanelControl, string textHeader, int _fontSize = 17)\n        {\n            GUILayout.BeginHorizontal();\n            GUILayout.Box(CPUtility.GetIcon(statePanelControl), GUIStyle.none,\n                GUILayout.Width(32), GUILayout.Height(32));\n            GUILayout.Space(3);\n            GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel)\n            {\n                fontSize = _fontSize\n            };\n            GUILayout.Label(textHeader, headerStyle, GUILayout.ExpandHeight(false), GUILayout.Height(31));\n            GUILayout.EndHorizontal();\n        }\n\n        public static void DrawHeader(string textHeader, int _fontSize = 16)\n        {\n            GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel)\n            {\n                fontSize = _fontSize\n            };\n            GUILayout.Label(textHeader, headerStyle);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/CPUtility.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b44fe5aa088e46d493f112ce6e0c9a40\ntimeCreated: 1706715670"
  },
  {
    "path": "VirtueSky/ControlPanel/ConstantControlPanel.cs",
    "content": "namespace VirtueSky.ControlPanel.Editor\n{\n    public class ConstantControlPanel\n    {\n        public static int WIDTH_CONTENT_BUTTON_STATE_CONTROL_PANEL = 210;\n        public static int POSITION_X_START_CONTENT = WIDTH_CONTENT_BUTTON_STATE_CONTROL_PANEL + 5;\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/ConstantControlPanel.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 88226ff529e4471d831fd11c0cf8be54\ntimeCreated: 1707216394"
  },
  {
    "path": "VirtueSky/ControlPanel/ConstantPackage.cs",
    "content": "﻿namespace VirtueSky.ControlPanel.Editor\n{\n    public class ConstantPackage\n    {\n        public const string VersionSunflower = \"3.5.5-preview\";\n        public const string PackageNameInAppPurchase = \"com.unity.purchasing\";\n        public const string MaxVersionInAppPurchase = \"5.0.2\";\n        public const string PackageNameNewtonsoftJson = \"com.unity.nuget.newtonsoft-json\";\n        public const string MaxVersionNewtonsoftJson = \"3.2.1\";\n        public const string PackageNameIOS14AdvertisingSupport = \"com.unity.ads.ios-support\";\n        public const string MaxVersionIOS14AdvertisingSupport = \"1.2.0\";\n        public const string PackageNameMobileNotification = \"com.unity.mobile.notifications\";\n        public const string MaxVersionMobileNotification = \"2.4.2\";\n        public const string PackageNameAddressables = \"com.unity.addressables\";\n        public const string MaxVersionAddressables = \"2.7.4\";\n\n        public const string PackageNameLevelPlay = \"com.unity.services.levelplay\";\n        public const string MaxVersionLevelPlay = \"9.4.0\";\n\n        public const string PackageNameAdmob = \"com.google.ads.mobile\";\n\n        public const string VersionAdmob =\n            \"https://github.com/googleads/googleads-mobile-unity.git?path=packages/com.google.ads.mobile#v11.0.0\";\n\n        #region Google Unity\n\n        public const string PackageNameGGPlayCore = \"com.google.play.core\";\n\n        public const string MaxVersionGGPlayCore =\n            \"https://github.com/RageAgainstThePixel/com.google.play.core.git#1.8.5\";\n\n        public const string PackageNameGGPlayCommon = \"com.google.play.common\";\n\n        public const string MaxVersionGGPlayCommon =\n            \"https://github.com/RageAgainstThePixel/com.google.play.common.git#1.9.2\";\n\n        public const string PackageNameGGExternalDependencyManager =\n            \"com.google.external-dependency-manager\";\n\n        public const string MaxVersionGGExternalDependencyManager =\n            \"https://github.com/googlesamples/unity-jar-resolver.git?path=upm#v1.2.187\";\n\n        public const string PackageNameGGPlayReview = \"com.google.play.review\";\n\n        public const string MaxVersionGGPlayReview =\n            \"https://github.com/pancake-llc/in-app-review.git#1.8.3\";\n\n        #endregion\n\n        #region Firebase\n\n        public const string PackageNameFirebaseApp = \"com.google.firebase.app\";\n\n        public const string MaxVersionFirebaseApp =\n            \"https://github.com/RageAgainstThePixel/com.google.firebase.app.git#13.10.0\";\n\n        public const string PackageNameFirebaseRemoteConfig = \"com.google.firebase.remote-config\";\n\n        public const string MaxVersionFirebaseRemoteConfig =\n            \"https://github.com/RageAgainstThePixel/com.google.firebase.remote-config.git#13.10.0\";\n\n        public const string PackageNameFirebaseAnalytics = \"com.google.firebase.analytics\";\n\n        public const string MaxVersionFirebaseAnalytics =\n            \"https://github.com/RageAgainstThePixel/com.google.firebase.analytics.git#13.10.0\";\n\n        public const string PackageNameFirebaseDatabase = \"com.google.firebase.database\";\n\n        public const string MaxVersionFirebaseDatabase =\n            \"https://github.com/RageAgainstThePixel/com.google.firebase.database.git#13.10.0\";\n\n        public const string PackageNameFirebaseAuth = \"com.google.firebase.auth\";\n\n        public const string MaxVersionFirebaseAuth =\n            \"https://github.com/RageAgainstThePixel/com.google.firebase.auth.git#13.10.0\";\n\n        public const string PackageNameFirebaseCrashlytics = \"com.google.firebase.crashlytics\";\n\n        public const string MaxVersionFirebaseCrashlytics =\n            \"https://github.com/RageAgainstThePixel/com.google.firebase.crashlytics.git#13.10.0\";\n\n        #endregion\n\n        public const string PackageNameAdjust = \"com.adjust.sdk\";\n        public const string MaxVersionAdjust = \"https://github.com/adjust/unity_sdk.git?path=Assets/Adjust#v5.5.1\";\n        public const string PackageNamePlayFab = \"com.pancake.playfab\";\n\n        public const string MaxVersionPlayFab =\n            \"https://github.com/pancake-llc/playfab.git#2.183.231124\";\n\n        public const string PackageNameAppFlyer = \"appsflyer-unity-plugin\";\n\n        public const string MaxVersionAppFlyer =\n            \"https://github.com/AppsFlyerSDK/appsflyer-unity-plugin.git?path=Assets/AppsFlyer#6.17.81\";\n\n        public const string PackageNameCoffeeUIEffect = \"com.coffee.ui-effect\";\n\n        public const string MaxVersionCoffeeUIEffect =\n            \"https://github.com/mob-sakai/UIEffect.git?path=Packages/src#5.10.8\";\n\n        public const string PackageNameCoffeeUIParticle = \"com.coffee.ui-particle\";\n\n        public const string MaxVersionCoffeeUIParticle =\n            \"https://github.com/mob-sakai/ParticleEffectForUGUI.git#4.12.1\";\n\n        public const string PackageNameAppleSignIn = \"com.lupidan.apple-signin-unity\";\n\n        public const string MaxVersionAppleSignIn =\n            \"https://github.com/lupidan/apple-signin-unity.git?path=Source#1.5.0\";\n\n        #region Spine\n\n        public const string PackageNameSpineCsharp = \"com.esotericsoftware.spine.spine-csharp\";\n\n        public const string MaxVersionSpineCsharp =\n            \"https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-csharp/src#4.1\";\n\n        public const string PackageNameSpineUnity = \"com.esotericsoftware.spine.spine-unity\";\n\n        public const string MaxVersionSpineUnity =\n            \"https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-unity/Assets/Spine#4.1\";\n\n        #endregion\n\n        public const string PackageNameUniTask = \"com.cysharp.unitask\";\n\n        public const string MaxVersionUniTask =\n            \"https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10\";\n\n        public const string PackageNameBakingSheet = \"com.cathei.bakingsheet\";\n\n        public const string MaxVersionBakingSheet =\n            \"https://github.com/cathei/BakingSheet.git?path=UnityProject/Packages/com.cathei.bakingsheet#v4.1.3\";\n    }\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/ConstantPackage.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a63c47ff7afd4d19a7bf1c5d3c730433\ntimeCreated: 1704948203"
  },
  {
    "path": "VirtueSky/ControlPanel/ControlPanelWindowEditor.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.ControlPanel.Editor\n{\n    public class ControlPanelWindowEditor : EditorWindow\n    {\n        private StatePanelControl statePanelControl;\n        private Vector2 scrollButton = Vector2.zero;\n        private const string keySaveStatePanelControl = \"Window_StatePanelControl\";\n        private static StatePanelControl StatePanelControl\n        {\n            get => (StatePanelControl)EditorPrefs.GetInt(keySaveStatePanelControl, (int)StatePanelControl.About);\n            set => EditorPrefs.SetInt(keySaveStatePanelControl, (int)value);\n        }\n\n        [MenuItem(\"Sunflower/Magic Panel &1\", false, priority = 1)]\n        public static void ShowPanelControlWindow()\n        {\n            ControlPanelWindowEditor window =\n                GetWindow<ControlPanelWindowEditor>(\"Magic Panel\");\n\n            if (window == null)\n            {\n                Debug.LogError(\"Couldn't open the window!\");\n                return;\n            }\n\n            window.minSize = new Vector2(600, 300);\n            window.Show();\n        }\n\n\n        private void OnEnable() {\n            statePanelControl = StatePanelControl;\n            CPAdvertisingDrawer.OnEnable();\n            CPIapDrawer.OnEnable();\n            CPLevelEditorDrawer.OnEnable();\n            CPFolderIconDrawer.OnEnable();\n            CPAdjustDrawer.OnEnable();\n            CPAppsFlyerDrawer.OnEnable();\n            CPLocalizationDrawer.OnEnable();\n        }\n\n        private void OnDisable()\n        {\n            CPLevelEditorDrawer.OnDisable();\n        }\n\n        private void OnGUI()\n        {\n            GUILayout.BeginHorizontal();\n            GUILayout.FlexibleSpace();\n            CPUtility.DrawHeader(\"Magic Panel\", 17);\n            GUILayout.FlexibleSpace();\n            GUILayout.EndHorizontal();\n            GUILayout.Space(10);\n            Handles.color = Color.black;\n            Handles.DrawAAPolyLine(4, new Vector3(0, 30), new Vector3(position.width, 30));\n            // GuiLine(2, Color.black);\n            GUILayout.Space(10);\n            GUILayout.BeginHorizontal();\n            GUILayout.BeginVertical(GUILayout.Width(ConstantControlPanel.WIDTH_CONTENT_BUTTON_STATE_CONTROL_PANEL));\n            scrollButton = EditorGUILayout.BeginScrollView(scrollButton);\n            DrawButton();\n            EditorGUILayout.EndScrollView();\n            Handles.DrawAAPolyLine(4, new Vector3(ConstantControlPanel.POSITION_X_START_CONTENT, 30),\n                new Vector3(ConstantControlPanel.POSITION_X_START_CONTENT, position.height));\n\n            GUILayout.EndVertical();\n            DrawContent();\n            GUILayout.EndHorizontal();\n        }\n\n        void DrawButton()\n        {\n            DrawButtonChooseState(\"Advertising\", StatePanelControl.Advertising);\n            DrawButtonChooseState(\"In App Purchase\", StatePanelControl.InAppPurchase);\n            DrawButtonChooseState(\"Scriptable Event\", StatePanelControl.SO_Event);\n            DrawButtonChooseState(\"Scriptable Variable\", StatePanelControl.SO_Variable);\n            DrawButtonChooseState(\"Audio\", StatePanelControl.Audio);\n            DrawButtonChooseState(\"Firebase\", StatePanelControl.Firebase);\n            DrawButtonChooseState(\"Adjust\", StatePanelControl.Adjust);\n            DrawButtonChooseState(\"AppsFlyer\", StatePanelControl.AppsFlyer);\n            DrawButtonChooseState(\"Assets Finder\", StatePanelControl.AssetsFinder);\n            DrawButtonChooseState(\"In App Review\", StatePanelControl.InAppReview);\n            DrawButtonChooseState(\"Level Editor\", StatePanelControl.LevelEditor);\n            DrawButtonChooseState(\"Localization\", StatePanelControl.Localization);\n            DrawButtonChooseState(\"Game Service\", StatePanelControl.GameService);\n            DrawButtonChooseState(\"Folder Icon\", StatePanelControl.FolderIcon);\n            DrawButtonChooseState(\"Hierarchy\", StatePanelControl.Hierarchy);\n            DrawButtonChooseState(\"Notifications\", StatePanelControl.NotificationsChanel);\n            DrawButtonChooseState(\"Scripting Define Symbols\", StatePanelControl.ScriptDefineSymbols);\n            DrawButtonChooseState(\"Register Package\", StatePanelControl.RegisterPackage);\n            DrawButtonChooseState(\"Extensions\", StatePanelControl.Extensions);\n            DrawButtonChooseState(\"About\", StatePanelControl.About);\n        }\n\n        void DrawContent()\n        {\n            switch (statePanelControl)\n            {\n                case StatePanelControl.Advertising:\n                    CPAdvertisingDrawer.OnDrawAdvertising();\n                    break;\n                case StatePanelControl.InAppPurchase:\n                    CPIapDrawer.OnDrawIap(position);\n                    break;\n                case StatePanelControl.AssetsFinder:\n                    CPAssetFinderDrawer.OnDrawAssetUsageDetector();\n                    break;\n                case StatePanelControl.Audio:\n                    CPAudioDrawer.OnDrawAudio(position, this);\n                    break;\n                case StatePanelControl.InAppReview:\n                    CPInAppReviewDrawer.OnDrawInAppReview(position);\n                    break;\n                case StatePanelControl.LevelEditor:\n                    CPLevelEditorDrawer.OnDrawLevelEditor(position);\n                    break;\n                case StatePanelControl.NotificationsChanel:\n                    CPNotificationChanelDrawer.OnDrawNotificationChanel(position);\n                    break;\n                case StatePanelControl.SO_Event:\n                    CPSoEventDrawer.OnDrawSoEvent();\n                    break;\n                case StatePanelControl.SO_Variable:\n                    CPSoVariableDrawer.OnDrawSoVariable();\n                    break;\n                case StatePanelControl.ScriptDefineSymbols:\n                    CPScriptingDefineSymbolsDrawer.OnDrawScriptingDefineSymbols();\n                    break;\n                case StatePanelControl.RegisterPackage:\n                    CPRegisterPackageDrawer.OnDrawRegisterPackageByManifest(position);\n                    break;\n                case StatePanelControl.FolderIcon:\n                    CPFolderIconDrawer.OnDrawFolderIcon();\n                    break;\n                case StatePanelControl.Hierarchy:\n                    CPHierarchyDrawer.OnDrawQHierarchyEvent(position, this);\n                    break;\n                case StatePanelControl.Firebase:\n                    CPFirebaseDrawer.OnDrawFirebase(position);\n                    break;\n                case StatePanelControl.Localization:\n                    CPLocalizationDrawer.OnDrawLocalization(position);\n                    break;\n                case StatePanelControl.Adjust:\n                    CPAdjustDrawer.OnDrawAdjust();\n                    break;\n                case StatePanelControl.AppsFlyer:\n                    CPAppsFlyerDrawer.OnDrawAppsFlyer();\n                    break;\n                case StatePanelControl.GameService:\n                    CPGameServiceDrawer.OnDrawGameService();\n                    break;\n                case StatePanelControl.Extensions:\n                    CPExtensionsDrawer.OnDrawExtensions(position);\n                    break;\n                case StatePanelControl.About:\n                    CPAboutDrawer.OnDrawAbout(position);\n                    break;\n            }\n        }\n\n\n        void DrawButtonChooseState(string title, StatePanelControl _statePanelControlTab)\n        {\n            GUILayout.BeginHorizontal();\n            GUILayout.Space(5);\n            GUILayout.Box(CPUtility.GetIcon(_statePanelControlTab), GUIStyle.none, GUILayout.ExpandWidth(true),\n                GUILayout.Width(18), GUILayout.Height(18));\n            bool clicked = GUILayout.Toggle(_statePanelControlTab == statePanelControl, title, GUI.skin.button,\n                GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true), GUILayout.Height(20));\n            if (clicked && statePanelControl != _statePanelControlTab)\n            {\n                statePanelControl = _statePanelControlTab;\n                StatePanelControl = statePanelControl;\n            }\n\n            GUILayout.EndHorizontal();\n            GUILayout.Space(2);\n        }\n    }\n\n    public enum StatePanelControl\n    {\n        Advertising = 0,\n        InAppPurchase = 1,\n        AssetsFinder = 2,\n        Audio = 3,\n        InAppReview = 4,\n        LevelEditor = 5,\n        NotificationsChanel = 6,\n        SO_Event = 7,\n        SO_Variable = 8,\n        Adjust = 9,\n        AppsFlyer = 10,\n        ScriptDefineSymbols = 11,\n        RegisterPackage = 12,\n        Hierarchy = 13,\n        FolderIcon = 14,\n        Firebase = 15,\n        GameService = 16,\n        Localization = 17,\n        Extensions = 18,\n        About = 19,\n    }\n}\n"
  },
  {
    "path": "VirtueSky/ControlPanel/ControlPanelWindowEditor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: dfee25753bfd489e8abaf8774cdcae0a\ntimeCreated: 1704274678"
  },
  {
    "path": "VirtueSky/ControlPanel/Virtuesky.Sunflower.ControlPanel.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.ControlPanel.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:ea1af3c654880af4ca6bb44b012e055e\",\n        \"GUID:405e8b335a1c8114fb36942b7f97083f\",\n        \"GUID:8579ab42c9ab63d4bac5fb07bd390b46\",\n        \"GUID:dcf049c718e6d4d0b8bbcaf56be706c2\",\n        \"GUID:2e2b9634fb53a4c01af8453caa52e1b4\",\n        \"GUID:b1979aef4cc42ae46af23ce2c4c109cc\",\n        \"GUID:8bd745a7d8af04c528da60c6b56aa92a\",\n        \"GUID:ae37c1f040fc3574a93bca20d91449d9\",\n        \"GUID:e0f213a0782f8f74b8e336c82c8f43b8\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:32dbaa332e571bf429b7de517f75f074\",\n        \"GUID:0b6289df6f84a6f4b982ff72d23e0273\",\n        \"GUID:49674d15b25185649b7ec8ac5d378747\",\n        \"GUID:abd57f653a468a04c8d4e281527ff293\",\n        \"GUID:0566ef25681cb4cec8714d50dda26ad1\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:2ba9ab3e4292d6e4b81f0022dc854eee\",\n        \"GUID:ade1d0a32a74d554ab9bf506427a1b1b\",\n        \"GUID:877be62fd20bbdb489dd86ee21cee87d\",\n        \"GUID:5e9107a8f2499184ea26564811dda246\",\n        \"GUID:c7e7793e0b5d326429f90e6fd716775e\",\n        \"GUID:6a3996cca4c689e4597a79d47ef54353\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/ControlPanel/Virtuesky.Sunflower.ControlPanel.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 76b168df9f87b864c9d9ce43f6acd854\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ControlPanel.meta",
    "content": "fileFormatVersion: 2\nguid: 17354e00e1ed0484da96acaf3b238c08\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Editor/OptionalPropertyDrawer.cs",
    "content": "using UnityEditor;\nusing VirtueSky.Core;\n\nnamespace VirtueSky.CoreEditor\n{\n    using UnityEngine;\n\n    [CustomPropertyDrawer(typeof(Optional<>))]\n    public class OptionalPropertyDrawer : PropertyDrawer\n    {\n        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)\n        {\n            var valueProperty = property.FindPropertyRelative(\"value\");\n            return EditorGUI.GetPropertyHeight(valueProperty);\n        }\n\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            var valueProperty = property.FindPropertyRelative(\"value\");\n            var enabledProperty = property.FindPropertyRelative(\"enabled\");\n\n            EditorGUI.BeginProperty(position, label, property);\n            position.width -= 24;\n            EditorGUI.BeginDisabledGroup(!enabledProperty.boolValue);\n            EditorGUI.PropertyField(position, valueProperty, label, true);\n            EditorGUI.EndDisabledGroup();\n\n            int indent = EditorGUI.indentLevel;\n            EditorGUI.indentLevel = 0;\n            position.x += position.width + 24;\n            position.width = position.height = EditorGUI.GetPropertyHeight(enabledProperty);\n            position.x -= position.width;\n            EditorGUI.PropertyField(position, enabledProperty, GUIContent.none);\n            EditorGUI.indentLevel = indent;\n            EditorGUI.EndProperty();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Editor/OptionalPropertyDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2d8179426da74b03ae16a1eda240e031\ntimeCreated: 1729237567"
  },
  {
    "path": "VirtueSky/Core/Editor/VirtueSky.Sunflower.Core.Editor.asmdef",
    "content": "{\n    \"name\": \"VirtueSky.Sunflower.Core.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Core/Editor/VirtueSky.Sunflower.Core.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: a62c674bc349edb45a02c380d4339bac\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 52d693025a653de41af12018e2396553\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime/App.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing UnityEngine;\nusing UnityEngine.Internal;\n\nnamespace VirtueSky.Core\n{\n    public struct App\n    {\n        private static MonoGlobal _monoGlobal;\n\n        public static void InitMonoGlobalComponent(MonoGlobal monoGlobal)\n        {\n            App._monoGlobal = monoGlobal;\n        }\n\n        public static void AddPauseCallback(Action<bool> callback)\n        {\n            _monoGlobal.OnGamePause -= callback;\n            _monoGlobal.OnGamePause += callback;\n        }\n\n        public static void RemovePauseCallback(Action<bool> callback)\n        {\n            _monoGlobal.OnGamePause -= callback;\n        }\n\n        public static void AddFocusCallback(Action<bool> callback)\n        {\n            _monoGlobal.OnGameFocus -= callback;\n            _monoGlobal.OnGameFocus += callback;\n        }\n\n        public static void RemoveFocusCallback(Action<bool> callback)\n        {\n            _monoGlobal.OnGameFocus -= callback;\n        }\n\n        public static void AddQuitCallback(Action callback)\n        {\n            _monoGlobal.OnGameQuit -= callback;\n            _monoGlobal.OnGameQuit += callback;\n        }\n\n        public static void RemoveQuitCallback(Action callback)\n        {\n            _monoGlobal.OnGameQuit -= callback;\n        }\n\n        #region Update\n\n        internal static void SubTick(IEntity tick)\n        {\n            _monoGlobal.AddTick(tick);\n        }\n\n        public static void SubTick(Action action)\n        {\n            _monoGlobal.AddTick(action);\n        }\n\n        internal static void SubFixedTick(IEntity fixedTick)\n        {\n            _monoGlobal.AddFixedTick(fixedTick);\n        }\n\n        public static void SubFixedTick(Action action)\n        {\n            _monoGlobal.AddFixedTick(action);\n        }\n\n        internal static void SubLateTick(IEntity lateTick)\n        {\n            _monoGlobal.AddLateTick(lateTick);\n        }\n\n        public static void SubLateTick(Action action)\n        {\n            _monoGlobal.AddLateTick(action);\n        }\n\n        internal static void UnSubTick(IEntity tick)\n        {\n            _monoGlobal.RemoveTick(tick);\n        }\n\n        public static void UnSubTick(Action action)\n        {\n            _monoGlobal.RemoveTick(action);\n        }\n\n        internal static void UnSubFixedTick(IEntity fixedTick)\n        {\n            _monoGlobal.RemoveFixedTick(fixedTick);\n        }\n\n        public static void UnSubFixedTick(Action action)\n        {\n            _monoGlobal.RemoveFixedTick(action);\n        }\n\n        internal static void UnSubLateTick(IEntity lateTick)\n        {\n            _monoGlobal.RemoveLateTick(lateTick);\n        }\n\n        public static void UnSubLateTick(Action action)\n        {\n            _monoGlobal.RemoveLateTick(action);\n        }\n\n        #endregion\n\n        #region DelayHandle\n\n        /// <summary>\n        /// Delay call\n        /// </summary>\n        /// <param name=\"duration\">The duration to wait before the DelayHandle fires.</param>\n        /// <param name=\"onComplete\">The action to run when the DelayHandle elapses.</param>\n        /// <param name=\"onUpdate\">A function to call each tick of the DelayHandle. Takes the number of seconds elapsed since\n        /// the start of the current cycle.</param>\n        /// <param name=\"isLooped\">Whether the DelayHandle should restart after executing.</param>\n        /// <param name=\"useRealTime\">Whether the DelayHandle uses real-time(not affected by slow-mo or pausing) or\n        /// game-time(affected by time scale changes).</param>\n        /// <returns></returns>\n        public static DelayHandle Delay(float duration, Action onComplete, Action<float> onUpdate = null,\n            bool isLooped = false, bool useRealTime = false)\n        {\n            var timer = new DelayHandle(duration,\n                onComplete,\n                onUpdate,\n                isLooped,\n                useRealTime,\n                null);\n            _monoGlobal.RegisterDelayHandle(timer);\n            return timer;\n        }\n\n\n        /// <summary>\n        /// Safe Delay call when it had target, progress delay will be cancel when target was destroyed\n        /// </summary>\n        /// <param name=\"duration\">The duration to wait before the DelayHandle fires.</param>\n        /// <param name=\"onComplete\">The action to run when the DelayHandle elapses.</param>\n        /// <param name=\"onUpdate\">A function to call each tick of the DelayHandle. Takes the number of seconds elapsed since\n        /// the start of the current cycle.</param>\n        /// <param name=\"isLooped\">Whether the DelayHandle should restart after executing.</param>\n        /// <param name=\"useRealTime\">Whether the DelayHandle uses real-time(not affected by slow-mo or pausing) or\n        /// game-time(affected by time scale changes).</param>\n        /// <param name=\"target\">The target (behaviour) to attach this DelayHandle to.</param>\n        public static DelayHandle Delay(\n            MonoBehaviour target,\n            float duration,\n            Action onComplete,\n            Action<float> onUpdate = null,\n            bool isLooped = false,\n            bool useRealTime = false)\n        {\n            var timer = new DelayHandle(duration,\n                onComplete,\n                onUpdate,\n                isLooped,\n                useRealTime,\n                target);\n            _monoGlobal.RegisterDelayHandle(timer);\n            return timer;\n        }\n\n        public static void CancelDelay(DelayHandle delayHandle)\n        {\n            delayHandle?.Cancel();\n        }\n\n        public static void PauseDelay(DelayHandle delayHandle)\n        {\n            delayHandle?.Pause();\n        }\n\n        public static void ResumeDelay(DelayHandle delayHandle)\n        {\n            delayHandle?.Resume();\n        }\n\n        public static void CancelAllDelay()\n        {\n            _monoGlobal.CancelAllDelayHandle();\n        }\n\n        public static void PauseAllDelay()\n        {\n            _monoGlobal.PauseAllDelayHandle();\n        }\n\n        public static void ResumeAllDelay()\n        {\n            _monoGlobal.ResumeAllDelayHandle();\n        }\n\n        #endregion\n\n        #region Effective\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Coroutine StartCoroutine(IEnumerator routine) => _monoGlobal.StartCoroutineImpl(routine);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Coroutine StartCoroutine(string methodName, [DefaultValue(\"null\")] object value) =>\n            _monoGlobal.StartCoroutineImpl(methodName, value);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Coroutine StartCoroutine(string methodName) => _monoGlobal.StartCoroutineImpl(methodName);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static void StopCoroutine(IEnumerator routine) => _monoGlobal.StopCoroutineImpl(routine);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static void StopCoroutine(Coroutine routine) => _monoGlobal.StopCoroutineImpl(routine);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static void StopCoroutine(string methodName) => _monoGlobal.StopCoroutineImpl(methodName);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static void StopAllCoroutine() => _monoGlobal.StopAllCoroutinesImpl();\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Action ToMainThread(Action action) => _monoGlobal.ToMainThreadImpl(action);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Action<T> ToMainThread<T>(Action<T> action) => _monoGlobal.ToMainThreadImpl(action);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Action<T1, T2> ToMainThread<T1, T2>(Action<T1, T2> action) =>\n            _monoGlobal.ToMainThreadImpl(action);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static Action<T1, T2, T3> ToMainThread<T1, T2, T3>(Action<T1, T2, T3> action) =>\n            _monoGlobal.ToMainThreadImpl(action);\n\n        [System.Runtime.CompilerServices.MethodImpl(\n            System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n        public static void RunOnMainThread(Action action) => _monoGlobal.RunOnMainThreadImpl(action);\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/App.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 04501404729040cf9c419e7c25c26f06\ntimeCreated: 1696306333"
  },
  {
    "path": "VirtueSky/Core/Runtime/BaseMono.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Core\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class BaseMono : MonoBehaviour, IEntity\n    {\n        public virtual void OnEnable()\n        {\n            SubTick();\n        }\n\n        public virtual void OnDisable()\n        {\n            UnSubTick();\n        }\n\n\n        public virtual void Initialize()\n        {\n        }\n\n        public virtual void Tick()\n        {\n        }\n\n        public virtual void LateTick()\n        {\n        }\n\n        public virtual void FixedTick()\n        {\n        }\n\n        public virtual void CleanUp()\n        {\n        }\n\n        void SubTick()\n        {\n            App.SubTick(this);\n            App.SubLateTick(this);\n            App.SubFixedTick(this);\n        }\n\n        void UnSubTick()\n        {\n            App.UnSubTick(this);\n            App.UnSubLateTick(this);\n            App.UnSubFixedTick(this);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/BaseMono.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d730116726f0ce342bfe91266ac72fdf\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime/BaseSO.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Core\n{\n    public class BaseSO : ScriptableObject, IEntity\n    {\n        [GUIColor(0.8f, 1.0f, 0.6f), Space(10), SerializeField, TextArea(2, 5)]\n        private string description;\n\n        public void Enable()\n        {\n            SubTick();\n        }\n\n        public void Disable()\n        {\n            UnSubTick();\n        }\n\n        void SubTick()\n        {\n            App.SubTick(this);\n            App.SubLateTick(this);\n            App.SubFixedTick(this);\n        }\n\n        public virtual void Initialize()\n        {\n        }\n\n        public virtual void Tick()\n        {\n        }\n\n        public virtual void LateTick()\n        {\n        }\n\n        public virtual void FixedTick()\n        {\n        }\n\n        public virtual void CleanUp()\n        {\n        }\n\n        public virtual void Destroy()\n        {\n        }\n\n        void UnSubTick()\n        {\n            App.UnSubTick(this);\n            App.UnSubLateTick(this);\n            App.UnSubFixedTick(this);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/BaseSO.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8e70f299e69a94d48863d0a992365d4f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime/CacheComponent.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.Core\n{\n    public class CacheComponent<T> : BaseMono\n    {\n        public T component;\n        public Transform CacheTransform { get; private set; }\n\n        protected virtual void Awake()\n        {\n            if (CacheTransform == null) CacheTransform = transform;\n            GetCacheComponent();\n        }\n\n        void GetCacheComponent()\n        {\n            if (component == null)\n            {\n                component = GetComponent<T>();\n            }\n        }\n#if UNITY_EDITOR\n        protected virtual void Reset()\n        {\n            GetCacheComponent();\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/CacheComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5a85bc3831bb51b4aa481a822db6e50d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime/DelayHandle.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Core\n{\n    public class DelayHandle\n    {\n        /// <summary>\n        /// How long the timer takes to complete from start to finish.\n        /// </summary>\n        public float Duration { get; private set; }\n\n        /// <summary>\n        /// Whether the timer will run again after completion.\n        /// </summary>\n        public bool IsLooped { get; set; }\n\n        /// <summary>\n        /// Whether or not the timer completed running. This is false if the timer was cancelled.\n        /// </summary>\n        public bool IsCompleted { get; private set; }\n\n        /// <summary>\n        /// Whether the timer uses real-time or game-time. Real time is unaffected by changes to the timescale\n        /// of the game(e.g. pausing, slow-mo), while game time is affected.\n        /// </summary>\n        public bool UsesRealTime { get; private set; }\n\n        /// <summary>\n        /// Whether the timer is currently paused.\n        /// </summary>\n        public bool IsPaused => _timeElapsedBeforePause.HasValue;\n\n        /// <summary>\n        /// Whether or not the timer was cancelled.\n        /// </summary>\n        public bool IsCancelled => _timeElapsedBeforeCancel.HasValue;\n\n        /// <summary>\n        /// Get whether or not the timer has finished running for any reason.\n        /// </summary>\n        public bool IsDone => IsCompleted || IsCancelled || IsOwnerDestroyed;\n\n\n        private bool IsOwnerDestroyed => _hasAutoDestroyOwner && _autoDestroyOwner == null;\n\n        private readonly Action _onComplete;\n        private readonly Action<float> _onUpdate;\n        private float _startTime;\n        private float _lastUpdateTime;\n\n        // for pausing, we push the start time forward by the amount of time that has passed.\n        // this will mess with the amount of time that elapsed when we're cancelled or paused if we just\n        // check the start time versus the current world time, so we need to cache the time that was elapsed\n        // before we paused/cancelled\n        private float? _timeElapsedBeforeCancel;\n        private float? _timeElapsedBeforePause;\n\n        // after the auto destroy owner is destroyed, the timer will expire\n        // this way you don't run into any annoying bugs with timers running and accessing objects\n        // after they have been destroyed\n        private readonly MonoBehaviour _autoDestroyOwner;\n        private readonly bool _hasAutoDestroyOwner;\n\n\n        /// <summary>\n        /// Stop a timer that is in-progress or paused. The timer's on completion callback will not be called.\n        /// </summary>\n        public void Cancel()\n        {\n            if (IsDone)\n            {\n                return;\n            }\n\n            _timeElapsedBeforeCancel = GetTimeElapsed();\n            _timeElapsedBeforePause = null;\n        }\n\n        /// <summary>\n        /// Pause a running timer. A paused timer can be resumed from the same point it was paused.\n        /// </summary>\n        public void Pause()\n        {\n            if (IsPaused || IsDone)\n            {\n                return;\n            }\n\n            _timeElapsedBeforePause = GetTimeElapsed();\n        }\n\n        /// <summary>\n        /// Continue a paused timer. Does nothing if the timer has not been paused.\n        /// </summary>\n        public void Resume()\n        {\n            if (!IsPaused || IsDone)\n            {\n                return;\n            }\n\n            _timeElapsedBeforePause = null;\n        }\n\n        /// <summary>\n        /// Get how many seconds have elapsed since the start of this timer's current cycle.\n        /// </summary>\n        /// <returns>The number of seconds that have elapsed since the start of this timer's current cycle, i.e.\n        /// the current loop if the timer is looped, or the start if it isn't.\n        ///\n        /// If the timer has finished running, this is equal to the duration.\n        ///\n        /// If the timer was cancelled/paused, this is equal to the number of seconds that passed between the timer\n        /// starting and when it was cancelled/paused.</returns>\n        public float GetTimeElapsed()\n        {\n            if (IsCompleted || GetWorldTime() >= GetFireTime())\n            {\n                return Duration;\n            }\n\n            return _timeElapsedBeforeCancel ?? _timeElapsedBeforePause ?? GetWorldTime() - _startTime;\n        }\n\n        /// <summary>\n        /// Get how many seconds remain before the timer completes.\n        /// </summary>\n        /// <returns>The number of seconds that remain to be elapsed until the timer is completed. A timer\n        /// is only elapsing time if it is not paused, cancelled, or completed. This will be equal to zero\n        /// if the timer completed.</returns>\n        public float GetTimeRemaining()\n        {\n            return Duration - GetTimeElapsed();\n        }\n\n        /// <summary>\n        /// Get how much progress the timer has made from start to finish as a ratio.\n        /// </summary>\n        /// <returns>A value from 0 to 1 indicating how much of the timer's duration has been elapsed.</returns>\n        public float GetRatioComplete()\n        {\n            return GetTimeElapsed() / Duration;\n        }\n\n        /// <summary>\n        /// Get how much progress the timer has left to make as a ratio.\n        /// </summary>\n        /// <returns>A value from 0 to 1 indicating how much of the timer's duration remains to be elapsed.</returns>\n        public float GetRatioRemaining()\n        {\n            return GetTimeRemaining() / Duration;\n        }\n\n\n        internal DelayHandle(float duration, Action onComplete, Action<float> onUpdate, bool isLooped,\n            bool usesRealTime, MonoBehaviour autoDestroyOwner)\n        {\n            Duration = duration;\n            _onComplete = onComplete;\n            _onUpdate = onUpdate;\n\n            IsLooped = isLooped;\n            UsesRealTime = usesRealTime;\n\n            _autoDestroyOwner = autoDestroyOwner;\n            _hasAutoDestroyOwner = autoDestroyOwner != null;\n\n            _startTime = GetWorldTime();\n            _lastUpdateTime = _startTime;\n        }\n\n        private float GetWorldTime()\n        {\n            return UsesRealTime ? Time.realtimeSinceStartup : Time.time;\n        }\n\n        private float GetFireTime()\n        {\n            return _startTime + Duration;\n        }\n\n        private float GetTimeDelta()\n        {\n            return GetWorldTime() - _lastUpdateTime;\n        }\n\n        internal void Update()\n        {\n            if (IsDone) return;\n\n            if (IsPaused)\n            {\n                _startTime += GetTimeDelta();\n                _lastUpdateTime = GetWorldTime();\n                return;\n            }\n\n            _lastUpdateTime = GetWorldTime();\n            _onUpdate?.Invoke(GetTimeElapsed());\n\n            if (GetWorldTime() >= GetFireTime())\n            {\n                _onComplete?.Invoke();\n\n                if (IsLooped) _startTime = GetWorldTime();\n                else IsCompleted = true;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/DelayHandle.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ccbac69e48a48b08e59b9ec4fff3c4b\ntimeCreated: 1711449985"
  },
  {
    "path": "VirtueSky/Core/Runtime/IEntity.cs",
    "content": "﻿namespace VirtueSky.Core\n{\n    public interface IEntity\n    {\n        void Initialize();\n        void Tick();\n        void LateTick();\n        void FixedTick();\n        void CleanUp();\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/IEntity.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ef029fe4bbaf08c458fe914d4788a11e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime/MonoGlobal.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.Internal;\nusing VirtueSky.DataStorage;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Core\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class MonoGlobal : MonoBehaviour\n    {\n        private readonly List<Action> _toMainThreads = new();\n        private volatile bool _isToMainThreadQueueEmpty = true;\n        private List<Action> _localToMainThreads = new();\n        internal event Action<bool> OnGamePause;\n        internal event Action OnGameQuit;\n        internal event Action<bool> OnGameFocus;\n        internal event Action OnTick;\n        internal event Action OnFixedTick;\n        internal event Action OnLateTick;\n\n        #region Sub / UnSub For Update Procresses\n\n        internal void AddTick(IEntity tick)\n        {\n            OnTick += tick.Tick;\n        }\n\n        internal void AddTick(Action action)\n        {\n            OnTick += action;\n        }\n\n        internal void AddFixedTick(IEntity fixedTick)\n        {\n            OnFixedTick += fixedTick.FixedTick;\n        }\n\n        internal void AddFixedTick(Action action)\n        {\n            OnFixedTick += action;\n        }\n\n        internal void AddLateTick(IEntity lateTick)\n        {\n            OnLateTick += lateTick.LateTick;\n        }\n\n        internal void AddLateTick(Action action)\n        {\n            OnLateTick += action;\n        }\n\n        internal void RemoveTick(IEntity tick)\n        {\n            OnTick -= tick.Tick;\n        }\n\n        internal void RemoveTick(Action action)\n        {\n            OnTick -= action;\n        }\n\n        internal void RemoveFixedTick(IEntity fixedTick)\n        {\n            OnFixedTick -= fixedTick.FixedTick;\n        }\n\n        internal void RemoveFixedTick(Action action)\n        {\n            OnFixedTick -= action;\n        }\n\n        internal void RemoveLateTick(IEntity lateTick)\n        {\n            OnLateTick -= lateTick.LateTick;\n        }\n\n        internal void RemoveLateTick(Action action)\n        {\n            OnLateTick -= action;\n        }\n\n        #endregion\n\n        #region Update Handle\n\n        private void Update()\n        {\n            OnTick?.Invoke();\n            UpdateAllDelayHandle();\n\n            if (_isToMainThreadQueueEmpty) return;\n            _localToMainThreads.Clear();\n            lock (_toMainThreads)\n            {\n                for (var i = 0; i < _toMainThreads.Count; i++)\n                {\n                    _localToMainThreads.Add(_toMainThreads[i]);\n                }\n\n                _toMainThreads.Clear();\n                _isToMainThreadQueueEmpty = true;\n            }\n\n            for (int i = 0; i < _localToMainThreads.Count; i++)\n            {\n                _localToMainThreads[i].Invoke();\n            }\n        }\n\n        private void FixedUpdate()\n        {\n            OnFixedTick?.Invoke();\n        }\n\n        private void LateUpdate()\n        {\n            OnLateTick?.Invoke();\n        }\n\n        #endregion\n\n        #region App Handle\n\n        private void OnApplicationFocus(bool hasFocus)\n        {\n            OnGameFocus?.Invoke(hasFocus);\n        }\n\n        private void OnApplicationPause(bool pauseStatus)\n        {\n            OnGamePause?.Invoke(pauseStatus);\n            if (pauseStatus && GameData.IsAutoSave)\n            {\n                GameData.Save();\n            }\n        }\n\n        private void OnApplicationQuit()\n        {\n            OnGameQuit?.Invoke();\n            if (GameData.IsAutoSave)\n            {\n                GameData.Save();\n            }\n        }\n\n        #endregion\n\n        #region delay handle\n\n        private List<DelayHandle> _timers = new();\n\n        // buffer adding timers so we don't edit a collection during iteration\n        private List<DelayHandle> _timersToAdd = new();\n        //private int _fixedFrameCount;\n\n        internal void RegisterDelayHandle(DelayHandle delayHandle)\n        {\n            _timersToAdd.Add(delayHandle);\n        }\n\n        internal void CancelAllDelayHandle()\n        {\n            for (var i = 0; i < _timers.Count; i++)\n            {\n                _timers[i].Cancel();\n            }\n\n            _timers = new List<DelayHandle>();\n            _timersToAdd = new List<DelayHandle>();\n        }\n\n        internal void PauseAllDelayHandle()\n        {\n            for (var i = 0; i < _timers.Count; i++)\n            {\n                _timers[i].Pause();\n            }\n        }\n\n        internal void ResumeAllDelayHandle()\n        {\n            for (var i = 0; i < _timers.Count; i++)\n            {\n                _timers[i].Resume();\n            }\n        }\n\n        private void UpdateAllDelayHandle()\n        {\n            if (_timersToAdd.Count > 0)\n            {\n                for (var i = 0; i < _timersToAdd.Count; i++)\n                {\n                    _timers.Add(_timersToAdd[i]);\n                }\n\n                _timersToAdd.Clear();\n            }\n\n            for (var i = 0; i < _timers.Count; i++)\n            {\n                _timers[i].Update();\n            }\n\n            _timers.RemoveAll(t => t.IsDone);\n        }\n\n        #endregion\n\n        #region Effective\n\n        internal Coroutine StartCoroutineImpl(IEnumerator routine)\n        {\n            if (routine != null)\n            {\n                return StartCoroutine(routine);\n            }\n\n            return null;\n        }\n\n        internal Coroutine StartCoroutineImpl(string methodName, [DefaultValue(\"null\")] object value)\n        {\n            if (!string.IsNullOrEmpty(methodName))\n            {\n                return StartCoroutine(methodName, value);\n            }\n\n            return null;\n        }\n\n        internal Coroutine StartCoroutineImpl(string methodName)\n        {\n            if (!string.IsNullOrEmpty(methodName))\n            {\n                return StartCoroutine(methodName);\n            }\n\n            return null;\n        }\n\n        internal void StopCoroutineImpl(IEnumerator routine)\n        {\n            if (routine != null) StopCoroutine(routine);\n        }\n\n        internal void StopCoroutineImpl(Coroutine routine)\n        {\n            if (routine != null) StopCoroutine(routine);\n        }\n\n        internal void StopCoroutineImpl(string methodName)\n        {\n            if (!string.IsNullOrEmpty(methodName))\n            {\n                StopCoroutine(methodName);\n            }\n        }\n\n        internal void StopAllCoroutinesImpl()\n        {\n            StopAllCoroutines();\n        }\n\n        /// <summary>\n        /// Schedules the specifies action to be run on the main thread (game thread).\n        /// The action will be invoked upon the next Unity Update event.\n        /// </summary>\n        /// <param name=\"action\">Action.</param>\n        internal void RunOnMainThreadImpl(Action action)\n        {\n            lock (_toMainThreads)\n            {\n                _toMainThreads.Add(action);\n                _isToMainThreadQueueEmpty = false;\n            }\n        }\n\n        /// <summary>\n        /// Converts the specified action to one that runs on the main thread.\n        /// The converted action will be invoked upon the next Unity Update event.\n        /// </summary>\n        /// <returns>The main thread.</returns>\n        /// <param name=\"action\">Act.</param>\n        internal Action ToMainThreadImpl(Action action)\n        {\n            if (action == null) return delegate { };\n            return () => RunOnMainThreadImpl(action);\n        }\n\n        /// <summary>\n        /// Converts the specified action to one that runs on the main thread.\n        /// The converted action will be invoked upon the next Unity Update event.\n        /// </summary>\n        /// <returns>The main thread.</returns>\n        /// <param name=\"action\">Act.</param>\n        /// <typeparam name=\"T\">The 1st type parameter.</typeparam>\n        internal Action<T> ToMainThreadImpl<T>(Action<T> action)\n        {\n            if (action == null) return delegate { };\n            return (arg) => RunOnMainThreadImpl(() => action(arg));\n        }\n\n        /// <summary>\n        /// Converts the specified action to one that runs on the main thread.\n        /// The converted action will be invoked upon the next Unity Update event.\n        /// </summary>\n        /// <returns>The main thread.</returns>\n        /// <param name=\"action\">Act.</param>\n        /// <typeparam name=\"T1\">The 1st type parameter.</typeparam>\n        /// <typeparam name=\"T2\">The 2nd type parameter.</typeparam>\n        internal Action<T1, T2> ToMainThreadImpl<T1, T2>(Action<T1, T2> action)\n        {\n            if (action == null) return delegate { };\n            return (arg1, arg2) => RunOnMainThreadImpl(() => action(arg1, arg2));\n        }\n\n        /// <summary>\n        /// Converts the specified action to one that runs on the main thread.\n        /// The converted action will be invoked upon the next Unity Update event.\n        /// </summary>\n        /// <returns>The main thread.</returns>\n        /// <param name=\"action\">Act.</param>\n        /// <typeparam name=\"T1\">The 1st type parameter.</typeparam>\n        /// <typeparam name=\"T2\">The 2nd type parameter.</typeparam>\n        /// <typeparam name=\"T3\">The 3rd type parameter.</typeparam>\n        internal Action<T1, T2, T3> ToMainThreadImpl<T1, T2, T3>(Action<T1, T2, T3> action)\n        {\n            if (action == null) return delegate { };\n            return (arg1, arg2, arg3) => RunOnMainThreadImpl(() => action(arg1, arg2, arg3));\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/MonoGlobal.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b35e41f4eb7743208efa75519c589e87\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime/Optional.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Core\n{\n    [Serializable]\n    public struct Optional<T>\n    {\n        [SerializeField] private bool enabled;\n        [SerializeField] private T value;\n\n        public bool Enabled => enabled;\n        public T Value => value;\n\n        public Optional(T value)\n            : this()\n        {\n            enabled = true;\n            this.value = value;\n        }\n\n        public Optional(bool enabled, T value)\n        {\n            this.enabled = enabled;\n            this.value = value;\n        }\n\n        public static implicit operator Optional<T>(T v)\n        {\n            return new Optional<T>(v);\n        }\n\n        public static implicit operator T(Optional<T> o)\n        {\n            return o.Value;\n        }\n\n        public static implicit operator bool(Optional<T> o)\n        {\n            return o.enabled;\n        }\n\n        public static bool operator ==(Optional<T> lhs, Optional<T> rhs)\n        {\n            if (lhs.Value is null) return rhs.Value is null;\n            return lhs.Value.Equals(rhs.Value);\n        }\n\n        public static bool operator !=(Optional<T> lhs, Optional<T> rhs)\n        {\n            return !(lhs == rhs);\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (Value is null) return obj is null;\n            return Value.Equals(obj);\n        }\n\n        public override int GetHashCode()\n        {\n            return Value.GetHashCode();\n        }\n\n        public override string ToString()\n        {\n            return Value.ToString();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/Optional.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e10115a70c8348a5a8eb3852528c7702\ntimeCreated: 1729158369"
  },
  {
    "path": "VirtueSky/Core/Runtime/RuntimeInitialize.cs",
    "content": "using UnityEngine;\nusing VirtueSky.DataStorage;\n\nnamespace VirtueSky.Core\n{\n    public class RuntimeInitialize\n    {\n        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]\n        private static void AutoInitialize()\n        {\n            var app = new GameObject(\"MonoGlobal\");\n            App.InitMonoGlobalComponent(app.AddComponent<MonoGlobal>());\n            GameData.Init();\n            Object.DontDestroyOnLoad(app);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/RuntimeInitialize.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2934229b05d34a618ea9472220392439\ntimeCreated: 1695109832"
  },
  {
    "path": "VirtueSky/Core/Runtime/UnityServiceInitialization.cs",
    "content": "#if VIRTUESKY_UNITY_SERVICES\nusing Unity.Services.Core;\nusing Unity.Services.Core.Environments;\n#endif\nusing UnityEngine;\n\nnamespace VirtueSky.Core\n{\n    public class UnityServiceInitialization : MonoBehaviour\n    {\n        private enum Environment\n        {\n            Production,\n            Development,\n        }\n\n        [SerializeField] private Environment environment = Environment.Production;\n\n        public static bool IsUnityServiceReady { get; private set; }\n\n        private void Awake()\n        {\n            Init();\n        }\n\n        private async void Init()\n        {\n#if VIRTUESKY_UNITY_SERVICES\n            IsUnityServiceReady = false;\n            var options = new InitializationOptions();\n            options.SetEnvironmentName(environment.ToString().ToLower());\n            await UnityServices.InitializeAsync(options);\n            IsUnityServiceReady = true;\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/UnityServiceInitialization.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cc3bfe5d4d6342a28dc707cf2416ee41\ntimeCreated: 1734073870"
  },
  {
    "path": "VirtueSky/Core/Runtime/virtuesky.sunflower.core.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Core\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:32dbaa332e571bf429b7de517f75f074\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:fe25561d224ed4743af4c60938a59d0b\",\n        \"GUID:70ea675efa2644cef98c7ece24158333\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Core/Runtime/virtuesky.sunflower.core.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: acb3cac55c622ec459c8caadf707623a\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: aaf872875f30d65418f32602e058c14e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Core.meta",
    "content": "fileFormatVersion: 2\nguid: 0ad9f466005576c409d885df4181be0e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage/Editor/DataWindowEditor.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Misc;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.DataStorage\n{\n#if UNITY_EDITOR\n    public class DataWindowEditor : EditorWindow\n    {\n        [MenuItem(\"Sunflower/Clear All Data\", priority = 501)]\n        public static void ClearAllData()\n        {\n            GameData.DeleteAll();\n            GameData.DeleteFileData();\n            PlayerPrefs.DeleteAll();\n            Debug.Log($\"Clear all data succeed\".SetColor(Color.green));\n        }\n\n        [MenuItem(\"Sunflower/Save Data\", priority = 504)]\n        public static void SaveData()\n        {\n            GameData.Save();\n            Debug.Log($\"Save data succeed\".SetColor(Color.green));\n        }\n\n        [MenuItem(\"Sunflower/Clear Path Data\", priority = 502)]\n        public static void ClearSunDataPath()\n        {\n            GameData.DeleteAll();\n            GameData.DeleteFileData();\n            Debug.Log($\"Clear sun path data succeed\".SetColor(Color.green));\n        }\n\n        [MenuItem(\"Sunflower/Open Path Data\", priority = 503)]\n        public static void OpenSunPathData()\n        {\n            string path = GameData.GetPersistentDataPath();\n            switch (SystemInfo.operatingSystemFamily)\n            {\n                case OperatingSystemFamily.Windows:\n                    FileExtension.OpenFolderInExplorer(path);\n                    break;\n                case OperatingSystemFamily.MacOSX:\n                    FileExtension.OpenFolderInFinder(path);\n                    break;\n            }\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/DataStorage/Editor/DataWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c5c23c930aa10314cb0e5a542e6e0ba0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage/Editor/Virtuesky.Sunflower.DataStorage.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.DataStorage.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:32dbaa332e571bf429b7de517f75f074\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/DataStorage/Editor/Virtuesky.Sunflower.DataStorage.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 0b6289df6f84a6f4b982ff72d23e0273\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: bfa5a0f266824bc45b9bdb52f45ff7e8\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime/GameData.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Runtime.CompilerServices;\nusing UnityEngine;\n\nnamespace VirtueSky.DataStorage\n{\n    public static class GameData\n    {\n        private static bool isInitialized;\n        private static int profile;\n        private static Dictionary<string, byte[]> datas = new();\n        private const int INIT_SIZE = 64;\n\n        public static bool IsAutoSave { get; set; } = true;\n        public static event Action OnSaveEvent;\n\n        #region Internal Stuff\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Init()\n        {\n            if (isInitialized) return;\n            isInitialized = true;\n            Load();\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static byte[] Serialize<T>(T data)\n        {\n            return SerializeAdapter.ToBinary(data);\n        }\n\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static T Deserialize<T>(byte[] bytes)\n        {\n            return SerializeAdapter.FromBinary<T>(bytes);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private static void RequireNullCheck()\n        {\n            if (datas == null) Load();\n            if (datas == null) throw new NullReferenceException();\n        }\n\n        private static string GetPath => GetDataPath($\"data_{profile}.sun\");\n\n        static string GetDataPath(string name)\n        {\n            var persistentDataPath = GetPersistentDataPath();\n            if (!Directory.Exists(persistentDataPath))\n            {\n                Directory.CreateDirectory(persistentDataPath);\n            }\n\n            return Path.Combine(persistentDataPath, name);\n        }\n\n        public static string GetPersistentDataPath()\n        {\n#if UNITY_EDITOR\n            return Path.Combine(Directory.GetParent(Application.dataPath).FullName, \"TempDataStorage\");\n#else\n            return Application.persistentDataPath;\n#endif\n        }\n\n        #endregion\n\n        #region Public API\n\n        public static bool IsInitialized => isInitialized;\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void ChangeProfile(int profile)\n        {\n            if (GameData.profile == profile) return;\n\n            Save();\n            GameData.profile = profile;\n            Load();\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool VerifyProfile(int profile)\n        {\n            return GameData.profile == profile;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Save()\n        {\n            OnSaveEvent?.Invoke();\n\n            byte[] bytes = Serialize(datas);\n            File.WriteAllBytes(GetPath, bytes);\n        }\n\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static async void SaveAsync()\n        {\n            OnSaveEvent?.Invoke();\n\n            byte[] bytes = Serialize(datas);\n            await File.WriteAllBytesAsync(GetPath, bytes);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Load()\n        {\n            if (!File.Exists(GetPath))\n            {\n                var stream = File.Create(GetPath);\n                stream.Close();\n            }\n\n            byte[] bytes = File.ReadAllBytes(GetPath);\n            if (bytes.Length == 0)\n            {\n                datas.Clear();\n                return;\n            }\n\n            datas = Deserialize<Dictionary<string, byte[]>>(bytes) ?? new Dictionary<string, byte[]>(INIT_SIZE);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static async void LoadAsync()\n        {\n            if (!File.Exists(GetPath))\n            {\n                var stream = File.Create(GetPath);\n                stream.Close();\n            }\n\n            byte[] bytes = await File.ReadAllBytesAsync(GetPath);\n            if (bytes.Length == 0)\n            {\n                datas.Clear();\n                return;\n            }\n\n            datas = Deserialize<Dictionary<string, byte[]>>(bytes) ?? new Dictionary<string, byte[]>(INIT_SIZE);\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <param name=\"default\">If value of <paramref name=\"key\"/> can not be found or empty! will return the default value of data type!</param>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T Get<T>(string key, T @default = default)\n        {\n            RequireNullCheck();\n\n            datas.TryGetValue(key, out byte[] value);\n            if (value == null || value.Length == 0) return @default;\n\n            return Deserialize<T>(value);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool TryGet<T>(string key, out T data)\n        {\n            RequireNullCheck();\n\n            bool hasKey;\n            if (datas.TryGetValue(key, out byte[] value))\n            {\n                data = Deserialize<T>(value);\n                hasKey = true;\n            }\n            else\n            {\n                data = default;\n                hasKey = false;\n            }\n\n            return hasKey;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Set<T>(string key, T data)\n        {\n            RequireNullCheck();\n            byte[] bytes = Serialize(data);\n            if (datas.TryAdd(key, bytes)) return;\n            datas[key] = bytes;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool HasKey(string key) => datas.ContainsKey(key);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void DeleteKey(string key) => datas.Remove(key);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void DeleteAll() => datas.Clear();\n\n        public static void DeleteFileData()\n        {\n            if (File.Exists(GetPath))\n            {\n                File.Delete(GetPath);\n            }\n        }\n\n        /// <summary>\n        /// Get raw byte[] of all data of profile\n        /// </summary>\n        /// <returns></returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static byte[] Backup()\n        {\n            return SerializeAdapter.ToBinary(datas);\n        }\n\n        /// <summary>\n        /// Load from byte[]\n        /// </summary>\n        /// <param name=\"bytes\"></param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Restore(byte[] bytes)\n        {\n            datas = SerializeAdapter.FromBinary<Dictionary<string, byte[]>>(bytes);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime/GameData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2c2791a2d0e74b7eb99e7f60a5c321a6\ntimeCreated: 1708533098"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime/SerializeAdapter.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Unity.Collections;\nusing Unity.Collections.LowLevel.Unsafe;\nusing Unity.Collections.LowLevel.Unsafe.NotBurstCompatible;\nusing Unity.Serialization.Binary;\n\nnamespace VirtueSky.DataStorage\n{\n    public static class SerializeAdapter\n    {\n        /// <summary>\n        /// Serializes the object to binary using the provided adapters.\n        /// Adapters provide control over how serialization is processed.\n        /// </summary>\n        /// <param name=\"obj\"></param>\n        /// <param name=\"adapters\"></param>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        public static unsafe byte[] ToBinary<T>(T obj, IReadOnlyList<IBinaryAdapter> adapters = null)\n        {\n            var buffer = new UnsafeAppendBuffer(16, 8, Allocator.Temp);\n            var parameters = new BinarySerializationParameters { UserDefinedAdapters = adapters?.ToList() };\n            BinarySerialization.ToBinary(&buffer, obj, parameters);\n\n            byte[] bytes = buffer.ToBytesNBC();\n            buffer.Dispose();\n\n            return bytes;\n        }\n\n        /// <summary>\n        /// Attemtps to deserialize a byte[] to the specified type using the provided adapters.\n        /// </summary>\n        /// <param name=\"serializedBytes\"></param>\n        /// <param name=\"adapters\"></param>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        public static unsafe T FromBinary<T>(byte[] serializedBytes, IReadOnlyList<IBinaryAdapter> adapters = null)\n        {\n            fixed (byte* ptr = serializedBytes)\n            {\n                var bufferReader = new UnsafeAppendBuffer.Reader(ptr, serializedBytes.Length);\n                var parameters = new BinarySerializationParameters { UserDefinedAdapters = adapters?.ToList() };\n                return BinarySerialization.FromBinary<T>(&bufferReader, parameters);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime/SerializeAdapter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d3289620c19f8444c92a482f8160889e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime/Virtuesky.Sunflower.DataStorage.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.DataStorage\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:2765e68924a08a94ea0ea66b31c0168f\",\n        \"GUID:e0cd26848372d4e5c891c569017e11f1\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": true,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [\n        {\n            \"name\": \"com.unity.serialization\",\n            \"expression\": \"3.1.1\",\n            \"define\": \"UNITY_SERIALIZATION\"\n        },\n        {\n            \"name\": \"com.unity.collections\",\n            \"expression\": \"2.1.4\",\n            \"define\": \"UNITY_SERIALIZATION\"\n        }\n    ],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime/Virtuesky.Sunflower.DataStorage.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 32dbaa332e571bf429b7de517f75f074\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: f50e6e7f3b71a1a46b9e1f8dc21804c1\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataStorage.meta",
    "content": "fileFormatVersion: 2\nguid: 791968b3b56ca3946a6a7051703192c5\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataType/DictionaryCustom.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.DataType\n{\n    [Serializable]\n    public class DictionaryCustom<TKey, TValue> : ISerializationCallbackReceiver, IDictionary, IDictionary<TKey, TValue>\n    {\n        [TableList, SerializeField] private List<DictionaryCustomData<TKey, TValue>> dictionaryData = new List<DictionaryCustomData<TKey, TValue>>();\n\n        [NonSerialized] private Dictionary<TKey, TValue> m_dict = new Dictionary<TKey, TValue>();\n        public Dictionary<TKey, TValue> GetDict => m_dict;\n\n        public void OnAfterDeserialize()\n        {\n            UpdateDict();\n        }\n\n        public void OnBeforeSerialize()\n        {\n            if (!Application.isPlaying) return;\n            UpdateList();\n        }\n\n        private void UpdateDict()\n        {\n            if (dictionaryData is { Count: > 0 })\n            {\n                if (m_dict is { Count: > 0 })\n                {\n                    m_dict.Clear();\n                }\n\n                foreach (var data in dictionaryData)\n                {\n                    if (data.key != null && data.value != null)\n                    {\n                        m_dict[data.key] = data.value;\n                    }\n                }\n            }\n        }\n\n        private void UpdateList()\n        {\n            dictionaryData.Clear();\n            if (m_dict is { Count: > 0 })\n            {\n                foreach (var kvp in m_dict)\n                {\n                    dictionaryData.Add(new DictionaryCustomData<TKey, TValue>(kvp.Key, kvp.Value));\n                }\n            }\n        }\n\n        public void Add(object key, object value)\n        {\n            m_dict.Add((TKey)key, (TValue)value);\n            UpdateList();\n        }\n\n        public void Add(KeyValuePair<TKey, TValue> item)\n        {\n            m_dict.Add(item.Key, item.Value);\n            UpdateList();\n        }\n\n        void ICollection<KeyValuePair<TKey, TValue>>.Clear()\n        {\n            m_dict.Clear();\n        }\n\n        public bool Contains(KeyValuePair<TKey, TValue> item)\n        {\n            return ((IDictionary)m_dict).Contains((TKey)item.Key);\n        }\n\n        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)\n        {\n            ((IDictionary<TKey, TValue>)m_dict).CopyTo(array, arrayIndex);\n        }\n\n        public bool Remove(KeyValuePair<TKey, TValue> item)\n        {\n            var result = ((IDictionary<TKey, TValue>)m_dict).Remove(item);\n            if (result) UpdateList();\n            return result;\n        }\n\n        public int Count => m_dict.Count;\n\n        public bool IsReadOnly => ((IDictionary)m_dict).IsReadOnly;\n\n\n        void IDictionary.Clear()\n        {\n            ((IDictionary<TKey, TValue>)m_dict).Clear();\n        }\n\n        public bool Contains(object key)\n        {\n            return ((IDictionary<TKey, TValue>)m_dict).Contains((KeyValuePair<TKey, TValue>)key);\n        }\n\n        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()\n        {\n            return ((IDictionary<TKey, TValue>)m_dict).GetEnumerator();\n        }\n\n        IDictionaryEnumerator IDictionary.GetEnumerator()\n        {\n            return ((IDictionary)m_dict).GetEnumerator();\n        }\n\n        public void Remove(object key)\n        {\n            m_dict.Remove((TKey)key);\n            UpdateList();\n        }\n\n        public bool IsFixedSize => ((IDictionary)m_dict).IsFixedSize;\n\n\n        public object this[object key]\n        {\n            get => ((IDictionary)m_dict)[key];\n            set => ((IDictionary)m_dict)[key] = value;\n        }\n\n        ICollection IDictionary.Keys => ((IDictionary)m_dict).Keys;\n\n        ICollection<TValue> IDictionary<TKey, TValue>.Values => (ICollection<TValue>)((IDictionary)m_dict).Values;\n\n        ICollection<TKey> IDictionary<TKey, TValue>.Keys => (ICollection<TKey>)((IDictionary)m_dict).Keys;\n\n        ICollection IDictionary.Values => ((IDictionary)m_dict).Values;\n\n        public void Add(TKey key, TValue value)\n        {\n            m_dict.Add(key, value);\n            UpdateList();\n        }\n\n        public void Clear()\n        {\n            m_dict.Clear();\n            UpdateList();\n        }\n\n        public bool ContainsKey(TKey key)\n        {\n            return m_dict.ContainsKey(key);\n        }\n\n        public bool ContainsValue(TValue value)\n        {\n            return m_dict.ContainsValue(value);\n        }\n\n        public bool Remove(TKey key)\n        {\n            var result = m_dict.Remove(key);\n            if (result) UpdateList();\n            return result;\n        }\n\n        public bool Remove(TKey key, out TValue value)\n        {\n            var result = m_dict.Remove(key, out value);\n            if (result) UpdateList();\n            return result;\n        }\n\n        public int EnsureCapacity(int capacity)\n        {\n            return m_dict.EnsureCapacity(capacity);\n        }\n\n        public virtual bool Equals(object? obj)\n        {\n            return m_dict.Equals(obj);\n        }\n\n        public System.Collections.Generic.Dictionary<TKey, TValue>.Enumerator GetEnumerator()\n        {\n            return m_dict.GetEnumerator();\n        }\n\n        public virtual int GetHashCode()\n        {\n            return m_dict.GetHashCode();\n        }\n\n        public Type GetType()\n        {\n            return m_dict.GetType();\n        }\n\n        public virtual string? ToString()\n        {\n            return m_dict.ToString();\n        }\n\n        public void TrimExcess()\n        {\n            m_dict.TrimExcess();\n        }\n\n        public void TrimExcess(int capacity)\n        {\n            m_dict.TrimExcess(capacity);\n        }\n\n        public bool TryAdd(TKey key, TValue value)\n        {\n            var result = m_dict.TryAdd(key, value);\n            if (result) UpdateList();\n            return result;\n        }\n\n        public bool TryGetValue(TKey key, out TValue value)\n        {\n            return m_dict.TryGetValue(key, out value);\n        }\n\n        public TValue this[TKey key]\n        {\n            get => ((IDictionary<TKey, TValue>)m_dict)[key];\n            set => ((IDictionary<TKey, TValue>)m_dict)[key] = value;\n        }\n\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return ((IDictionary)m_dict).GetEnumerator();\n        }\n\n        public void CopyTo(Array array, int index)\n        {\n            ((IDictionary)m_dict).CopyTo(array, index);\n        }\n\n\n        public bool IsSynchronized => ((IDictionary)m_dict).IsSynchronized;\n        public object SyncRoot => ((IDictionary)m_dict).SyncRoot;\n        public System.Collections.Generic.Dictionary<TKey, TValue>.KeyCollection Keys => m_dict.Keys;\n        public System.Collections.Generic.Dictionary<TKey, TValue>.ValueCollection Values => m_dict.Values;\n    }\n\n    [Serializable]\n    public class DictionaryCustomData<TKey, TValue>\n    {\n        public TKey key;\n        public TValue value;\n\n        public DictionaryCustomData(TKey _key, TValue _value)\n        {\n            key = _key;\n            value = _value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/DataType/DictionaryCustom.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f566d8a0c4f24f2d8406864e8db1571d\ntimeCreated: 1721577270"
  },
  {
    "path": "VirtueSky/DataType/ShortDouble.Units.cs",
    "content": "using System;\r\n\r\nnamespace VirtueSky.DataType\r\n{\r\n    public partial struct ShortDouble\r\n    {\r\n        static Unit FindUnit(double value)\r\n        {\r\n            return _unitFinder.Invoke(value);\r\n        }\r\n\r\n        public static class Unit0\r\n        {\r\n            static readonly Unit[] Units;\r\n            static readonly Unit Infinity;\r\n            static readonly Unit Zero;\r\n\r\n            static Unit0()\r\n            {\r\n                Infinity.exponent = 0;\r\n                Infinity.name = \"(VeryBIG)\";\r\n                Zero.exponent = 0;\r\n                Zero.name = \"\";\r\n\r\n                Units = new Unit[120];\r\n                var i = 0;\r\n\r\n                Units[i++].name = \"\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"k\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"m\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"b\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"t\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n\r\n                for (var c0 = 'a'; c0 <= 'z'; c0++)\r\n                {\r\n                    for (var c1 = c0; c1 <= 'z'; c1++)\r\n                    {\r\n                        if (i >= Units.Length)\r\n                        {\r\n                            break;\r\n                        }\r\n\r\n                        Units[i++].name = c0.ToString() + c1.ToString();\r\n                        Units[i - 1].exponent = (i - 1) * 3;\r\n                    }\r\n                }\r\n            }\r\n\r\n            public static Unit Find(double value)\r\n            {\r\n                //extract\r\n\r\n                var e = Math.Log10(Math.Abs(value));\r\n                var fe = Math.Floor(e);\r\n\r\n                var exponent = Math.DivRem((long)fe, 3, out _) * 3;\r\n\r\n                //find\r\n                if (exponent < 0)\r\n                    return Zero;\r\n                return exponent / 3 < Units.Length ? Units[exponent / 3] : Infinity;\r\n            }\r\n        }\r\n\r\n        public static class Unit1\r\n        {\r\n            static readonly Unit[] Units;\r\n            static readonly Unit Infinity;\r\n            static readonly Unit Zero;\r\n\r\n            static Unit1()\r\n            {\r\n                Infinity.exponent = 0;\r\n                Infinity.name = \"(VeryBIG)\";\r\n                Zero.exponent = 0;\r\n                Zero.name = \"\";\r\n\r\n                Units = new Unit[304];\r\n                var i = 0;\r\n\r\n                Units[i++].name = \"\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"K\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"M\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"B\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                Units[i++].name = \"T\";\r\n                Units[i - 1].exponent = (i - 1) * 3;\r\n\r\n                var exp = 14;\r\n                for (var j = i; j < Units.Length; j++)\r\n                {\r\n                    Units[j].name = \"e\" + (++exp);\r\n                    Units[j].exponent = exp;\r\n                }\r\n            }\r\n\r\n            public static Unit Find(double value)\r\n            {\r\n                //extract\r\n                long exponent;\r\n\r\n                var e = Math.Log10(Math.Abs(value));\r\n                var fe = Math.Floor(e);\r\n\r\n                if (fe < 15)\r\n                {\r\n                    exponent = Math.DivRem((long)fe, 3, out _) * 3;\r\n                }\r\n                else\r\n                    exponent = (long)fe;\r\n\r\n                //find\r\n                if (exponent < 0)\r\n                    return Zero;\r\n                if (exponent < 15)\r\n                    return Units[exponent / 3];\r\n                return exponent < Units.Length + 5 ? Units[15 / 3 + exponent - 15] : Infinity;\r\n            }\r\n        }\r\n\r\n        public static class Unit2\r\n        {\r\n            private static readonly Unit[] Units;\r\n            private static readonly Unit Infinity;\r\n            private static readonly Unit Zero;\r\n\r\n            private static readonly string[] Signs =\r\n            {\r\n                \"\", \"k\", \"m\", \"b\", \"t\", \"q\", \"Q\", \"s\", \"S\", \"o\", \"n\", \"d\", \"u\",\r\n                \"Du\", \"Tr\", \"Qu\", \"Qi\", \"Sx\", \"Sp\", \"Oc\", \"No\", \"Vi\", \"Ce\"\r\n            };\r\n\r\n            static Unit2()\r\n            {\r\n                Infinity.exponent = 0;\r\n                Infinity.name = \"(VeryBIG)\";\r\n                Zero.exponent = 0;\r\n                Zero.name = \"\";\r\n\r\n                Units = new Unit[Signs.Length];\r\n                for (var i = 0; i < Signs.Length; i++)\r\n                {\r\n                    Units[i].name = Signs[i];\r\n                    Units[i].exponent = i * 3;\r\n                }\r\n            }\r\n\r\n            public static Unit Find(double value)\r\n            {\r\n                var e = Math.Log10(Math.Abs(value));\r\n                var fe = Math.Floor(e);\r\n\r\n                var exponent = Math.DivRem((long)fe, 3, out long remainder) * 3;\r\n\r\n                if (exponent < 0)\r\n                    return Zero;\r\n                return exponent / 3 < Units.Length ? Units[exponent / 3] : Infinity;\r\n            }\r\n        }\r\n\r\n        public struct Unit\r\n        {\r\n            public int exponent;\r\n            public string name;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "VirtueSky/DataType/ShortDouble.Units.cs.meta",
    "content": "﻿fileFormatVersion: 2\r\nguid: 7c10ed2d72cf4d26ba8c0bdfe8ec3d7f\r\ntimeCreated: 1617701321"
  },
  {
    "path": "VirtueSky/DataType/ShortDouble.cs",
    "content": "﻿using System;\r\nusing System.Runtime.InteropServices;\r\nusing Newtonsoft.Json;\r\nusing UnityEditor;\r\nusing UnityEngine;\r\n\r\nnamespace VirtueSky.DataType\r\n{\r\n    [Serializable, JsonObject(MemberSerialization.OptIn)]\r\n    public partial struct ShortDouble : IFormattable, IComparable<ShortDouble>, IEquatable<ShortDouble>,\r\n        IComparable\r\n    {\r\n        static Func<double, Unit> _unitFinder;\r\n\r\n        static ShortDouble()\r\n        {\r\n            _unitFinder = Unit0.Find;\r\n        }\r\n\r\n        [SerializeField] double value;\r\n\r\n        public ShortDouble(double value = 0)\r\n        {\r\n            this.value = value;\r\n        }\r\n\r\n        public double Value => value;\r\n\r\n        // Implicit convert double to SecuredDouble\r\n        public static implicit operator ShortDouble(double value) => new ShortDouble(value);\r\n\r\n        // Implicit convert SecuredDouble to double\r\n        public static implicit operator double(ShortDouble value) => value.Value;\r\n\r\n        public static ShortDouble operator +(ShortDouble a, ShortDouble b) =>\r\n            new ShortDouble(a.Value + b.Value);\r\n\r\n        public static ShortDouble operator -(ShortDouble a, ShortDouble b) =>\r\n            new ShortDouble(a.Value - b.Value);\r\n\r\n        public static ShortDouble operator *(ShortDouble a, ShortDouble b) =>\r\n            new ShortDouble(a.Value * b.Value);\r\n\r\n        public static ShortDouble operator /(ShortDouble a, ShortDouble b) =>\r\n            new ShortDouble(a.Value / b.Value);\r\n\r\n        public static bool operator >(ShortDouble a, ShortDouble b) => a.Value > b.Value;\r\n        public static bool operator >=(ShortDouble a, ShortDouble b) => a.Value >= b.Value;\r\n        public static bool operator <(ShortDouble a, ShortDouble b) => a.Value < b.Value;\r\n        public static bool operator <=(ShortDouble a, ShortDouble b) => a.Value <= b.Value;\r\n\r\n        public ShortDouble Floor => new ShortDouble(Math.Floor(Value));\r\n        public ShortDouble Ceiling => new ShortDouble(Math.Ceiling(Value));\r\n        public ShortDouble Round => new ShortDouble(Math.Round(Value));\r\n\r\n        public float AsFloat() => (float)Value;\r\n        public long AsLong() => (long)Value;\r\n        public bool AsBool(float eps = 0.3f) => Value > eps;\r\n        public int AsInt() => (int)Value;\r\n        public bool True => AsBool();\r\n\r\n        public ShortDouble Pow(double p) => new ShortDouble(Math.Pow(Value, p));\r\n        public static ShortDouble Max(ShortDouble a, ShortDouble b) => a > b ? a : b;\r\n        public static ShortDouble Min(ShortDouble a, ShortDouble b) => a > b ? b : a;\r\n\r\n        public static ShortDouble Clamp(ShortDouble value, ShortDouble min, ShortDouble max) =>\r\n            value < min ? min : (value > max ? max : value);\r\n\r\n        public int CompareTo(ShortDouble other) => Value.CompareTo(other.Value);\r\n        public int CompareTo(object obj) => Value.CompareTo(obj);\r\n\r\n        public bool Equals(ShortDouble other) => Value.Equals(other.Value);\r\n\r\n        public override bool Equals(object other)\r\n        {\r\n            if (other == null || GetType() != other.GetType()) return false;\r\n            return Value.Equals(((ShortDouble)other).Value);\r\n        }\r\n\r\n        public override int GetHashCode() => Value.GetHashCode();\r\n\r\n        public override string ToString() => ToString(FindUnit(Value), \"0.#\");\r\n        public string ToString(string format) => ToString(FindUnit(Value), format);\r\n        public string ToString(IFormatProvider provider) => Value.ToString(provider);\r\n        public string ToString(string format, IFormatProvider provider) => ToString(FindUnit(Value), format, provider);\r\n\r\n        string ToString(Unit unit, string format = \"0.##\")\r\n        {\r\n            if (double.IsInfinity(Value) || double.IsNaN(Value))\r\n            {\r\n                return \"Infinity or NaN\";\r\n            }\r\n\r\n            return (Value / System.Math.Pow(10, unit.exponent)).ToString(format) + unit.name;\r\n        }\r\n\r\n        string ToString(Unit unit, string format, IFormatProvider provider)\r\n        {\r\n            if (double.IsInfinity(Value) || double.IsNaN(Value))\r\n            {\r\n                return \"Infinity or NaN\";\r\n            }\r\n\r\n            return (Value / System.Math.Pow(10, unit.exponent)).ToString(format, provider) + unit.name;\r\n        }\r\n\r\n        public static void SetUnit(int u)\r\n        {\r\n            if (u == 0)\r\n            {\r\n                _unitFinder = Unit0.Find;\r\n            }\r\n            else if (u == 1)\r\n            {\r\n                _unitFinder = Unit1.Find;\r\n            }\r\n            else\r\n            {\r\n                _unitFinder = Unit2.Find;\r\n            }\r\n        }\r\n    }\r\n\r\n#if UNITY_EDITOR\r\n    [CustomPropertyDrawer(typeof(ShortDouble))]\r\n    public class ShortDoubleDrawer : PropertyDrawer\r\n    {\r\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\r\n        {\r\n            EditorGUI.BeginProperty(position, label, property);\r\n\r\n            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);\r\n\r\n            var indent = EditorGUI.indentLevel;\r\n            EditorGUI.indentLevel = 0;\r\n            EditorGUI.PropertyField(position, property.FindPropertyRelative(\"value\"), GUIContent.none);\r\n            EditorGUI.indentLevel = indent;\r\n\r\n            EditorGUI.EndProperty();\r\n        }\r\n    }\r\n#endif\r\n}"
  },
  {
    "path": "VirtueSky/DataType/ShortDouble.cs.meta",
    "content": "fileFormatVersion: 2\r\nguid: 3a7fad66991554a129cbbd53d0878356\r\ntimeCreated: 1504925677\r\nlicenseType: Pro\r\nMonoImporter:\r\n  serializedVersion: 2\r\n  defaultReferences: []\r\n  executionOrder: 0\r\n  icon: {instanceID: 0}\r\n  userData: \r\n  assetBundleName: \r\n  assetBundleVariant: \r\n"
  },
  {
    "path": "VirtueSky/DataType/virtuesky.sunflower.datatype.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.DataType\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/DataType/virtuesky.sunflower.datatype.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 540154dd0c5ed9a4dbbe695c402232fb\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/DataType.meta",
    "content": "fileFormatVersion: 2\nguid: e272376fd682f6b46a867b4eab4fc8cc\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Editor/BaseEventEditor.cs",
    "content": "using System.Reflection;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    // [CustomEditor(typeof(BaseEvent), true)]\n    // public class BaseEventNoParamEditor : Editor\n    // {\n    //     private MethodInfo _methodInfo;\n    //\n    //     void OnEnable()\n    //     {\n    //         _methodInfo = target.GetType().BaseType.GetMethod(\"DebugRaiseEvent\",\n    //             BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n    //     }\n    //\n    //     public override void OnInspectorGUI()\n    //     {\n    //         base.OnInspectorGUI();\n    //         GUILayout.Space(10);\n    //         GUI.enabled = EditorApplication.isPlaying;\n    //         if (GUILayout.Button(\"Raise\"))\n    //         {\n    //             _methodInfo.Invoke(target, null);\n    //         }\n    //\n    //         GUI.enabled = true;\n    //     }\n    // }\n    //\n    // [CustomEditor(typeof(BaseEvent<>), true)]\n    // public class BaseEventParamEditor : UnityEditor.Editor\n    // {\n    //     private MethodInfo _methodInfo;\n    //\n    //     void OnEnable()\n    //     {\n    //         _methodInfo = target.GetType().BaseType.GetMethod(\"DebugRaiseEvent\",\n    //             BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n    //     }\n    //\n    //     public override void OnInspectorGUI()\n    //     {\n    //         base.OnInspectorGUI();\n    //         GUILayout.Space(10);\n    //         GUI.enabled = EditorApplication.isPlaying;\n    //         if (GUILayout.Button(\"Raise\"))\n    //         {\n    //             _methodInfo.Invoke(target, null);\n    //         }\n    //\n    //         GUI.enabled = true;\n    //     }\n    // }\n    //\n    // [CustomEditor(typeof(BaseEvent<,>), true)]\n    // public class BaseEventResultEditor : UnityEditor.Editor\n    // {\n    //     private MethodInfo _methodInfo;\n    //     private SerializedProperty _valueResult;\n    //\n    //     void OnEnable()\n    //     {\n    //         _methodInfo = target.GetType().BaseType.GetMethod(\"DebugRaiseEvent\",\n    //             BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n    //     }\n    //\n    //     public override void OnInspectorGUI()\n    //     {\n    //         base.OnInspectorGUI();\n    //         GUILayout.Space(10);\n    //         _valueResult = serializedObject.FindProperty(\"valueResult\");\n    //         GUI.enabled = EditorApplication.isPlaying;\n    //\n    //         if (GUILayout.Button(\"Raise\"))\n    //         {\n    //             _methodInfo.Invoke(target, null);\n    //         }\n    //\n    //         EditorGUILayout.PropertyField(_valueResult);\n    //         GUI.enabled = true;\n    //     }\n    // }\n}"
  },
  {
    "path": "VirtueSky/Events/Editor/BaseEventEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fe06611ca91e4ac7afd485ec6444c37a\ntimeCreated: 1708743122"
  },
  {
    "path": "VirtueSky/Events/Editor/EventWindowEditor.cs",
    "content": "using UnityEditor;\n\n\nnamespace VirtueSky.Events\n{\n#if UNITY_EDITOR\n    using VirtueSky.UtilsEditor;\n\n    public class EventWindowEditor : EditorWindow\n    {\n        #region Create ScriptableObject Event\n\n        private const string pathEvent = \"/Event\";\n        private const string menuEvent = \"Sunflower/Scriptable/Create Event/\";\n\n        [MenuItem(menuEvent + \"EventNoParam\")]\n        public static void CreateEventNoParam()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParam>(pathEvent, \"so_event_no_param\");\n        }\n\n        [MenuItem(menuEvent + \"String Event\")]\n        public static void CreateEventString()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEvent>(pathEvent, \"so_string_event\");\n        }\n\n        [MenuItem(menuEvent + \"Float Event\")]\n        public static void CreateEventFloat()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEvent>(pathEvent, \"so_float_event\");\n        }\n\n        [MenuItem(menuEvent + \"Integer Event\")]\n        public static void CreateEventInt()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntegerEvent>(pathEvent, \"so_int_event\");\n        }\n\n        [MenuItem(menuEvent + \"Boolean Event\")]\n        public static void CreateEventBoolean()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BooleanEvent>(pathEvent, \"so_bool_event\");\n        }\n\n        [MenuItem(menuEvent + \"Object Event\")]\n        public static void CreateEventObject()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEvent>(pathEvent, \"so_object_event\");\n        }\n\n        [MenuItem(menuEvent + \"Short Double Event\")]\n        public static void CreateEventShortDouble()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ShortDoubleEvent>(pathEvent, \"so_short_double_event\");\n        }\n\n        [MenuItem(menuEvent + \"Dictionary Event\")]\n        public static void CreateEventDictionary()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<DictionaryEvent>(pathEvent, \"so_dictionary_event\");\n        }\n\n        [MenuItem(menuEvent + \"Vector3 Event\")]\n        public static void CreateEventVector3()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3Event>(pathEvent, \"so_vector3_event\");\n        }\n\n        [MenuItem(menuEvent + \"Vector2 Event\")]\n        public static void CreateEventVector2()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector2Event>(pathEvent, \"so_vector2_event\");\n        }\n\n        [MenuItem(menuEvent + \"GameObject Event\")]\n        public static void CreateEventGameObject()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEvent>(pathEvent, \"so_gameobject_event\");\n        }\n\n        [MenuItem(menuEvent + \"Transform Event\")]\n        public static void CreateEventTransform()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEvent>(pathEvent, \"so_transform_event\");\n        }\n\n        #endregion\n\n        #region Create Scriptable Event Result\n\n        private const string pathEventResult = \"/Event_Result\";\n\n        private const string menuEventResult = \"Sunflower/Scriptable/Create Event-Result/\";\n\n\n        #region Bool Event - Result\n\n        private const string menuBoolEventResult = \"Bool Event/\";\n        private const string pathBoolEventResult = \"/Bool_Event_Result\";\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"Bool Result\")]\n        public static void CreateBoolEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventBoolResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"Float Result\")]\n        public static void CreateBoolEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventFloatResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"Int Result\")]\n        public static void CreateBoolEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventIntResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"Object Result\")]\n        public static void CreateBoolEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventObjectResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"String Result\")]\n        public static void CreateBoolEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventStringResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"Vector3 Result\")]\n        public static void CreateBoolEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventStringResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"GameObject Result\")]\n        public static void CreateBoolEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventGameObjectResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuBoolEventResult + \"Transform Result\")]\n        public static void CreateBoolEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<BoolEventTransformResult>(pathEventResult + pathBoolEventResult,\n                \"bool_event_transform_result\");\n        }\n\n        #endregion\n\n        #region Float Event - Result\n\n        private const string menuFloatEventResult = \"Float Event/\";\n        private const string pathFloatEventResult = \"/Float_Event_Result\";\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"Bool Result\")]\n        public static void CreateFloatEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventBoolResult>(pathEventResult + pathFloatEventResult,\n                \"float_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"Float Result\")]\n        public static void CreateFloatEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventFloatResult>(pathEventResult + pathFloatEventResult,\n                \"float_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"Int Result\")]\n        public static void CreateFloatEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventIntResult>(pathEventResult + pathFloatEventResult,\n                \"float_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"Object Result\")]\n        public static void CreateFloatEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventObjectResult>(pathEventResult + pathFloatEventResult,\n                \"float_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"String Result\")]\n        public static void CreateFloatEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventStringResult>(pathEventResult + pathFloatEventResult,\n                \"float_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"Vector3 Result\")]\n        public static void CreateFloatEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventStringResult>(pathEventResult + pathFloatEventResult,\n                \"float_event_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"GameObject Result\")]\n        public static void CreateFloatEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventGameObjectResult>(\n                pathEventResult + pathFloatEventResult,\n                \"float_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuFloatEventResult + \"Transform Result\")]\n        public static void CreateFloatEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<FloatEventTransformResult>(\n                pathEventResult + pathFloatEventResult,\n                \"float_event_transform_result\");\n        }\n\n        #endregion\n\n        #region Int Event - Result\n\n        private const string menuIntEventResult = \"Int Event/\";\n        private const string pathIntEventResult = \"/Int_Event_Result\";\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"Bool Result\")]\n        public static void CreateIntEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventBoolResult>(pathEventResult + pathIntEventResult,\n                \"int_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"Float Result\")]\n        public static void CreateIntEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventFloatResult>(pathEventResult + pathIntEventResult,\n                \"int_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"Int Result\")]\n        public static void CreateIntEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventIntResult>(pathEventResult + pathIntEventResult,\n                \"int_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"Object Result\")]\n        public static void CreateIntEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventObjectResult>(pathEventResult + pathIntEventResult,\n                \"int_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"String Result\")]\n        public static void CreateIntEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventStringResult>(pathEventResult + pathIntEventResult,\n                \"int_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"Vector3 Result\")]\n        public static void CreateIntEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventObjectResult>(pathEventResult + pathIntEventResult,\n                \"int_event_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"GameObject Result\")]\n        public static void CreateIntEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventGameObjectResult>(pathEventResult + pathIntEventResult,\n                \"int_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuIntEventResult + \"Transform Result\")]\n        public static void CreateIntEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<IntEventTransformResult>(pathEventResult + pathIntEventResult,\n                \"int_event_transform_result\");\n        }\n\n        #endregion\n\n        #region Object Event - Result\n\n        private const string menuObjectEventResult = \"Object Event/\";\n        private const string pathObjectEventResult = \"/Object_Event_Result\";\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"Bool Result\")]\n        public static void CreateObjectEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventBoolResult>(pathEventResult + pathObjectEventResult,\n                \"object_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"Float Result\")]\n        public static void CreateObjectEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventFloatResult>(pathEventResult + pathObjectEventResult,\n                \"object_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"Int Result\")]\n        public static void CreateObjectEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventIntResult>(pathEventResult + pathObjectEventResult,\n                \"object_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"Object Result\")]\n        public static void CreateObjectEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventObjectResult>(pathEventResult + pathObjectEventResult,\n                \"object_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"String Result\")]\n        public static void CreateObjectEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventStringResult>(pathEventResult + pathObjectEventResult,\n                \"object_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"Vector3 Result\")]\n        public static void CreateObjectEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventVector3Result>(\n                pathEventResult + pathObjectEventResult,\n                \"object_event_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"GameObject Result\")]\n        public static void CreateObjectEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventGameObjectResult>(\n                pathEventResult + pathObjectEventResult,\n                \"object_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuObjectEventResult + \"Transform Result\")]\n        public static void CreateObjectEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<ObjectEventTransformResult>(\n                pathEventResult + pathObjectEventResult,\n                \"object_event_transform_result\");\n        }\n\n        #endregion\n\n        #region String Event - Result\n\n        private const string menuStringEventResult = \"String Event/\";\n        private const string pathStringEventResult = \"/String_Event_Result\";\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"Bool Result\")]\n        public static void CreateStringEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventBoolResult>(pathEventResult + pathStringEventResult,\n                \"string_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"Float Result\")]\n        public static void CreateStringEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventFloatResult>(pathEventResult + pathStringEventResult,\n                \"string_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"Int Result\")]\n        public static void CreateStringEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventIntResult>(pathEventResult + pathStringEventResult,\n                \"string_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"Object Result\")]\n        public static void CreateStringEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventObjectResult>(pathEventResult + pathStringEventResult,\n                \"string_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"String Result\")]\n        public static void CreateStringEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventStringResult>(pathEventResult + pathStringEventResult,\n                \"string_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"Vector3 Result\")]\n        public static void CreateStringEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventVector3Result>(\n                pathEventResult + pathStringEventResult,\n                \"string_event_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"GameObject Result\")]\n        public static void CreateStringEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventGameObjectResult>(\n                pathEventResult + pathStringEventResult,\n                \"string_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuStringEventResult + \"Transform Result\")]\n        public static void CreateStringEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<StringEventTransformResult>(\n                pathEventResult + pathStringEventResult,\n                \"string_event_transform_result\");\n        }\n\n        #endregion\n\n        #region Vector3 Event - Result\n\n        private const string menuVector3EventResult = \"Vector3 Event/\";\n        private const string pathVector3EventResult = \"/Vector3_Event_Result\";\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"Bool Result\")]\n        public static void CreateVector3EventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventBoolResult>(pathEventResult + pathVector3EventResult,\n                \"vector3_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"Float Result\")]\n        public static void CreateVector3EventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventFloatResult>(\n                pathEventResult + pathVector3EventResult,\n                \"vector3_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"Int Result\")]\n        public static void CreateVector3EventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventIntResult>(pathEventResult + pathVector3EventResult,\n                \"vector3_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"Object Result\")]\n        public static void CreateVector3EventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventObjectResult>(\n                pathEventResult + pathVector3EventResult,\n                \"vector3_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"String Result\")]\n        public static void CreateVector3EventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventStringResult>(\n                pathEventResult + pathVector3EventResult,\n                \"vector3_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"Vector3 Result\")]\n        public static void CreateVector3EventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventVector3Result>(\n                pathEventResult + pathVector3EventResult,\n                \"vector3_event_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"GameObject Result\")]\n        public static void CreateVector3EventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventGameObjectResult>(\n                pathEventResult + pathVector3EventResult,\n                \"vector3_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuVector3EventResult + \"Transform Result\")]\n        public static void CreateVector3EventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<Vector3EventTransformResult>(\n                pathEventResult + pathVector3EventResult,\n                \"vector3_event_transform_result\");\n        }\n\n        #endregion\n\n        #region Event No Param - Result\n\n        private const string menuEventNoParamResult = \"Event No Param/\";\n        private const string pathEventNoParamResult = \"/Event_No_Param_Result\";\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"Bool Result\")]\n        public static void CreateEventNoParamBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamBoolResult>(pathEventResult + pathEventNoParamResult,\n                \"event_no_param_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"Float Result\")]\n        public static void CreateEventNoParamFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamFloatResult>(\n                pathEventResult + pathEventNoParamResult,\n                \"event_no_param_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"Int Result\")]\n        public static void CreateEventNoParamIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamIntResult>(pathEventResult + pathEventNoParamResult,\n                \"event_no_param_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"Object Result\")]\n        public static void CreateEventNoParamObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamObjectResult>(\n                pathEventResult + pathEventNoParamResult,\n                \"event_no_param_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"String Result\")]\n        public static void CreateEventNoParamStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamStringResult>(\n                pathEventResult + pathEventNoParamResult,\n                \"event_no_param_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"Vector3 Result\")]\n        public static void CreateEventNoParamVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamVector3Result>(\n                pathEventResult + pathEventNoParamResult,\n                \"event_no_param_vector3_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"GameObject Result\")]\n        public static void CreateEventNoParamGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamGameObjectResult>(\n                pathEventResult + pathEventNoParamResult,\n                \"event_no_param_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuEventNoParamResult + \"Transform Result\")]\n        public static void CreateEventNoParamTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<EventNoParamTransformResult>(\n                pathEventResult + pathEventNoParamResult,\n                \"event_no_param_transform_result\");\n        }\n\n        #endregion\n\n        #region GameObject Event - Result\n\n        private const string menuGameObjectEventResult = \"GameObject Event/\";\n        private const string pathGameObjectEventResult = \"/GameObject_Event_Result\";\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"Bool Result\")]\n        public static void CreateGameObjectEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventBoolResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"Float Result\")]\n        public static void CreateGameObjectEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventFloatResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"GameObject Result\")]\n        public static void CreateGameObjectEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventGameObjectResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"Int Result\")]\n        public static void CreateGameObjectEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventIntResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"Object Result\")]\n        public static void CreateGameObjectEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventObjectResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"String Result\")]\n        public static void CreateGameObjectEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventStringResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"Transform Result\")]\n        public static void CreateGameObjectEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventTransformResult>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_transform_result\");\n        }\n\n        [MenuItem(menuEventResult + menuGameObjectEventResult + \"Vector3 Result\")]\n        public static void CreateGameObjectEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<GameObjectEventVector3Result>(\n                pathEventResult + pathGameObjectEventResult,\n                \"gameobject_event_vector3_result\");\n        }\n\n        #endregion\n\n        #region Transform Event - Result\n\n        private const string menuTransformEventResult = \"Transform Event/\";\n        private const string pathTransformEventResult = \"/Transform_Event_Result\";\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"Bool Result\")]\n        public static void CreateTransformEventBoolResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventBoolResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_bool_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"Float Result\")]\n        public static void CreateTransformEventFloatResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventFloatResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_float_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"GameObject Result\")]\n        public static void CreateTransformEventGameObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventGameObjectResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_gameobject_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"Int Result\")]\n        public static void CreateTransformEventIntResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventIntResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_int_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"Object Result\")]\n        public static void CreateTransformEventObjectResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventObjectResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_object_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"String Result\")]\n        public static void CreateTransformEventStringResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventStringResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_string_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"Transform Result\")]\n        public static void CreateTransformEventTransformResult()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventTransformResult>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_transform_result\");\n        }\n\n        [MenuItem(menuEventResult + menuTransformEventResult + \"Vector3 Result\")]\n        public static void CreateTransformEventVector3Result()\n        {\n            CreateAsset.CreateScriptableAssetsOnlyName<TransformEventVector3Result>(\n                pathEventResult + pathTransformEventResult,\n                \"transform_event_vector3_result\");\n        }\n\n        #endregion\n\n        #endregion\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Events/Editor/EventWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d525cea821836b74681c2fd7108104c8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Editor/virtuesky.sunflower.event.editor.asmdef",
    "content": "{\n    \"name\": \"virtuesky.sunflower.event.editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Events/Editor/virtuesky.sunflower.event.editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: ae37c1f040fc3574a93bca20d91449d9\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 8c990f2aee3aee740b7cfb15c0f47dba\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/BaseEvent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    public class BaseEvent : BaseSO, IEvent\n    {\n        readonly List<IEventListener> listeners = new List<IEventListener>();\n\n        private Action onRaised = null;\n\n#if UNITY_EDITOR\n\n        [ShowIf(nameof(ConditionShow))]\n        [GUIColor(0.6f, 0.9f, 1.0f), Button(\"Raise\")]\n        private void DebugRaiseEvent()\n        {\n            Raise();\n        }\n\n        protected bool ConditionShow => EditorApplication.isPlaying;\n#endif\n        public void Raise()\n        {\n#if UNITY_EDITOR\n            // Debug.Log($\"===> {name}\");\n#endif\n            for (var i = listeners.Count - 1; i >= 0; i--)\n            {\n                listeners[i].OnEventRaised(this);\n            }\n\n            onRaised?.Invoke();\n        }\n\n\n        public event Action OnRaised\n        {\n            add => onRaised += value;\n            remove => onRaised -= value;\n        }\n\n        public void AddListener(Action action)\n        {\n            onRaised += action;\n        }\n\n        public void RemoveListener(Action action)\n        {\n            onRaised -= action;\n        }\n\n        public void AddListener(IEventListener listener)\n        {\n            if (!listeners.Contains(listener))\n            {\n                listeners.Add(listener);\n            }\n        }\n\n        public void RemoveListener(IEventListener listener)\n        {\n            if (listeners.Contains(listener))\n            {\n                listeners.Remove(listener);\n            }\n        }\n\n        public void RemoveAll()\n        {\n            listeners.Clear();\n            onRaised = null;\n        }\n    }\n\n    public class BaseEvent<TType> : BaseSO, IEvent<TType>\n    {\n        readonly List<IEventListener<TType>> listeners = new List<IEventListener<TType>>();\n        private Action<TType> onRaised = null;\n#if UNITY_EDITOR\n        [Space(10)] [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), SerializeField]\n        private TType valueDebug = default(TType);\n\n        [ShowIf(nameof(ConditionShow))]\n        [GUIColor(0.6f, 0.9f, 1.0f), Button(\"Raise\")]\n        private void DebugRaiseEvent()\n        {\n            Raise(valueDebug);\n        }\n\n        protected bool ConditionShow => EditorApplication.isPlaying;\n#endif\n\n        public virtual void Raise(TType value)\n        {\n#if UNITY_EDITOR\n            //Debug.Log($\"===> {name}\");\n#endif\n            for (var i = listeners.Count - 1; i >= 0; i--)\n            {\n                listeners[i].OnEventRaised(this, value);\n            }\n\n            onRaised?.Invoke(value);\n        }\n\n        public event Action<TType> OnRaised\n        {\n            add => onRaised += value;\n            remove => onRaised -= value;\n        }\n\n        public void AddListener(Action<TType> action)\n        {\n            onRaised += action;\n        }\n\n        public void RemoveListener(Action<TType> action)\n        {\n            onRaised -= action;\n        }\n\n        public void AddListener(IEventListener<TType> listener)\n        {\n            if (!listeners.Contains(listener))\n            {\n                listeners.Add(listener);\n            }\n        }\n\n        public void RemoveListener(IEventListener<TType> listener)\n        {\n            if (listeners.Contains(listener))\n            {\n                listeners.Remove(listener);\n            }\n        }\n\n        public void RemoveAll()\n        {\n            listeners.Clear();\n            onRaised = null;\n        }\n    }\n\n    public class BaseEvent<TType, TResult> : BaseSO, IEvent<TType, TResult>\n    {\n        readonly List<IEventListener<TType, TResult>> listeners = new List<IEventListener<TType, TResult>>();\n        private Func<TType, TResult> onRaised = null;\n\n#if UNITY_EDITOR\n        [Space(10)] [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), SerializeField]\n        private TType valueDebug = default(TType);\n\n        [ShowIf(nameof(ConditionShow))] [GUIColor(0.6f, 0.9f, 1.0f), ReadOnly, SerializeField]\n        private TResult valueResult = default(TResult);\n\n        [ShowIf(nameof(ConditionShow))]\n        [GUIColor(0.6f, 0.9f, 1.0f), Button(\"Raise\")]\n        private void DebugRaiseEvent()\n        {\n            valueResult = Raise(valueDebug);\n        }\n\n        protected bool ConditionShow => EditorApplication.isPlaying;\n#endif\n        public TResult Raise(TType value)\n        {\n            TResult result = default;\n            if (!Application.isPlaying) return result;\n            for (var i = listeners.Count - 1; i >= 0; i--)\n            {\n                listeners[i].OnEventRaised(this, value);\n            }\n\n            if (onRaised != null) result = onRaised.Invoke(value);\n            return result;\n        }\n\n        public event Func<TType, TResult> OnRaised\n        {\n            add { onRaised += value; }\n            remove { onRaised -= value; }\n        }\n\n\n        public void AddListener(Func<TType, TResult> func)\n        {\n            onRaised += func;\n        }\n\n        public void RemoveListener(Func<TType, TResult> func)\n        {\n            onRaised -= func;\n        }\n\n        public void AddListener(IEventListener<TType, TResult> listener)\n        {\n            if (!listeners.Contains(listener))\n            {\n                listeners.Add(listener);\n            }\n        }\n\n        public void RemoveListener(IEventListener<TType, TResult> listener)\n        {\n            if (listeners.Contains(listener))\n            {\n                listeners.Remove(listener);\n            }\n        }\n\n        public void RemoveAll()\n        {\n            listeners.Clear();\n            onRaised = null;\n        }\n    }\n\n#if UNITY_EDITOR\n\n\n#endif\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/BaseEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7f885e714ddc92849ac280af904bba4f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/BaseEventListener.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Events;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Events\n{\n    public class BaseEventListener<TEvent, TResponse> : EventListenerMono, IEventListener\n        where TEvent : BaseEvent\n        where TResponse : UnityEvent\n    {\n        [SerializeField] private EventResponseData[] listEventResponseDatas;\n        private readonly Dictionary<BaseEvent, UnityEvent> _dictionary = new Dictionary<BaseEvent, UnityEvent>();\n\n        [Serializable]\n        public class EventResponseData\n        {\n            public TEvent @event;\n            public TResponse response;\n#if UNITY_EDITOR\n            [ShowIf(nameof(ConditionShow))]\n            [Button(\"Raise\")]\n            void DebugRaise()\n            {\n                @event.Raise();\n            }\n\n            private bool ConditionShow => EditorApplication.isPlaying;\n#endif\n        }\n\n        protected override void ToggleListenerEvent(bool isListenerEvent)\n        {\n            if (isListenerEvent)\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    t.@event.AddListener(this);\n                    _dictionary.TryAdd(t.@event, t.response);\n                }\n            }\n            else\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    t.@event.RemoveListener(this);\n                    if (_dictionary.ContainsKey(t.@event)) _dictionary.Remove(t.@event);\n                }\n            }\n        }\n\n        public virtual void OnEventRaised(BaseEvent eventRaise)\n        {\n            _dictionary[eventRaise]?.Invoke();\n        }\n    }\n\n    public class BaseEventListener<TType, TEvent, TResponse> : EventListenerMono, IEventListener<TType>\n        where TEvent : BaseEvent<TType>\n        where TResponse : UnityEvent<TType>\n    {\n        [SerializeField] protected EventResponseData[] listEventResponseDatas;\n\n        protected readonly Dictionary<BaseEvent<TType>, UnityEvent<TType>> _dictionary =\n            new Dictionary<BaseEvent<TType>, UnityEvent<TType>>();\n\n        [Serializable]\n        public class EventResponseData\n        {\n            public TEvent @event;\n            public TResponse response;\n#if UNITY_EDITOR\n            [ShowIf(nameof(ConditionShow))] [SerializeField]\n            private TType valueDebug;\n\n            [ShowIf(nameof(ConditionShow))]\n            [Button(\"Raise\")]\n            void DebugRaise()\n            {\n                @event.Raise(valueDebug);\n            }\n\n            private bool ConditionShow => EditorApplication.isPlaying;\n#endif\n        }\n\n        protected override void ToggleListenerEvent(bool isListenerEvent)\n        {\n            if (isListenerEvent)\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    t.@event.AddListener(this);\n                    _dictionary.TryAdd(t.@event, t.response);\n                }\n            }\n            else\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    t.@event.RemoveListener(this);\n                    if (_dictionary.ContainsKey(t.@event)) _dictionary.Remove(t.@event);\n                }\n            }\n        }\n\n        public virtual void OnEventRaised(BaseEvent<TType> eventRaise, TType value)\n        {\n            _dictionary[eventRaise]?.Invoke(value);\n        }\n    }\n\n    public class BaseEventListener<TType, TResult, TEvent, TResponse> : EventListenerMono,\n        IEventListener<TType, TResult>\n        where TEvent : BaseEvent<TType, TResult>\n        where TResponse : UnityEvent<TType>\n    {\n        [SerializeField] protected EventResponseData[] listEventResponseDatas;\n\n        protected readonly Dictionary<BaseEvent<TType, TResult>, UnityEvent<TType>> _dictionary =\n            new Dictionary<BaseEvent<TType, TResult>, UnityEvent<TType>>();\n\n        [Serializable]\n        public class EventResponseData\n        {\n            public TEvent @event;\n            public TResponse response;\n        }\n\n        public void OnEventRaised(BaseEvent<TType, TResult> eventRaise, TType value)\n        {\n            _dictionary[eventRaise]?.Invoke(value);\n        }\n\n        protected override void ToggleListenerEvent(bool isListenerEvent)\n        {\n            if (isListenerEvent)\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    t.@event.AddListener(this);\n                    _dictionary.TryAdd(t.@event, t.response);\n                }\n            }\n            else\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    t.@event.RemoveListener(this);\n                    if (_dictionary.ContainsKey(t.@event)) _dictionary.Remove(t.@event);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/BaseEventListener.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1f85358eae4b4fedbec94383e714f35c\ntimeCreated: 1651562443"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/BaseEventResponse.cs",
    "content": "using UnityEngine.Events;\n\nnamespace VirtueSky.Events\n{\n    public class BaseEventResponse : UnityEvent, IEventResponse\n    {\n    }\n\n    public class BaseEventResponse<TType> : UnityEvent<TType>, IEventResponse\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/BaseEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 893521d098d1429489b6dc83598b1b1b\ntimeCreated: 1651574321"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/EventListenerMono.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    public abstract class EventListenerMono : MonoBehaviour\n    {\n        [SerializeField] private BindingListener bindingListener;\n\n        protected abstract void ToggleListenerEvent(bool isListenerEvent);\n\n        private void Awake()\n        {\n            if (bindingListener == BindingListener.UNTIL_DESTROY)\n            {\n                ToggleListenerEvent(true);\n            }\n        }\n\n        private void OnEnable()\n        {\n            if (bindingListener == BindingListener.UNTIL_DISABLE)\n            {\n                ToggleListenerEvent(true);\n            }\n        }\n\n        private void OnDisable()\n        {\n            if (bindingListener == BindingListener.UNTIL_DISABLE)\n            {\n                ToggleListenerEvent(false);\n            }\n        }\n\n        private void OnDestroy()\n        {\n            if (bindingListener == BindingListener.UNTIL_DESTROY)\n            {\n                ToggleListenerEvent(false);\n            }\n        }\n    }\n\n    public enum BindingListener\n    {\n        UNTIL_DISABLE,\n        UNTIL_DESTROY\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event/EventListenerMono.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ffc0d5f5a5ab4ba7a4702668f69ba09d\ntimeCreated: 1697612265"
  },
  {
    "path": "VirtueSky/Events/Runtime/Base_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 892c2cea0ad241878ecb12183ab37cb7\ntimeCreated: 1697617884"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/BooleanEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Boolean Event\", fileName = \"bool_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BooleanEvent : BaseEvent<bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/BooleanEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aef918ec277845979450b0fbea88e78b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/BooleanEventListener.cs",
    "content": "using VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class BooleanEventListener : BaseEventListener<bool, BooleanEvent, BooleanEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/BooleanEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fd08215cd3194a57bd070df5454b8d18\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/BooleanEventResponse.cs",
    "content": "using System;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class BooleanEventResponse : BaseEventResponse<bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/BooleanEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f5c01c8b67014dfb83f095ecacbb35f4\ntimeCreated: 1659151605"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/Boolean Result\",\n        fileName = \"bool_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventBoolResult : BaseEvent<bool, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7945a7b8329c496fa66fd66951b195ef\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/Float Result\",\n        fileName = \"bool_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventFloatResult : BaseEvent<bool, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 76ea5d4b4cc8493ebcef45f72a23608c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/GameObject Result\",\n        fileName = \"bool_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventGameObjectResult : BaseEvent<bool, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bfd630b8a8424ff781cf4af941463720\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/Int Result\",\n        fileName = \"bool_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventIntResult : BaseEvent<bool, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d23d33af0f7a4ca78fdbc1f5f0c51e04\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/Object Result\",\n        fileName = \"bool_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventObjectResult : BaseEvent<bool, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: be2e3ed588b74c61b261e24ebe469019\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/String Result\",\n        fileName = \"bool_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventStringResult : BaseEvent<bool, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6d3f4e07c1f843b28cba61dad278994d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/Transform Result\",\n        fileName = \"bool_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventTransformResult : BaseEvent<bool, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3827e644d1414c22818adb6ad27237ab\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Boolean Event/Vector3 Result\",\n        fileName = \"bool_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class BoolEventVector3Result : BaseEvent<bool, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result/BoolEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ec64add237eb452a90562dadaf8d8cbf\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 14a616b32e884ca78656c271efb32461\ntimeCreated: 1708746295"
  },
  {
    "path": "VirtueSky/Events/Runtime/Boolean_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 6b45161106b8fd241b098ad985d4938e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Custom/ClickButtonEvent.cs",
    "content": "using VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event\")]\n    public class ClickButtonEvent : EventNoParam\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Custom/ClickButtonEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 34f5aa4023cc40ee952b894df1be543c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Custom.meta",
    "content": "fileFormatVersion: 2\nguid: c58a6109373d49e3b55b1d33844e1ee6\ntimeCreated: 1720080443"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEvent.cs",
    "content": "﻿using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/DictionaryEvent\", fileName = \"dictionary_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class DictionaryEvent : BaseEvent<Dictionary<string, object>>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 814787ad80ba44cea17a4a3b6d536ef1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventListener.cs",
    "content": "using System.Collections.Generic;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class\n        DictionaryEventListener : BaseEventListener<Dictionary<string, object>, DictionaryEvent,\n        DictionaryEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 566e31263e25463eb7afbf70fdc47acc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventResponse.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class DictionaryEventResponse : BaseEventResponse<Dictionary<string, object>>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event/DictionaryEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 55e065f206f040459d9ddb559fd3ad40\ntimeCreated: 1659155254"
  },
  {
    "path": "VirtueSky/Events/Runtime/Dictionary_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 341bcf9b0a48d1d4583485ea7d08fc3c\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/EventListenerNoParam.cs",
    "content": "using VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class EventListenerNoParam : BaseEventListener<EventNoParam, EventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/EventListenerNoParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f477bc0650f64520ad655afc7aacef99\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/EventNoParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Event No Param\", fileName = \"event_no_param\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParam : BaseEvent\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/EventNoParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 719558c56beb4a8d98cf058fadf5455a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/EventResponse.cs",
    "content": "using System;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class EventResponse : BaseEventResponse\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/EventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: dbe3c2bf266f40799ca5f846bd5b42e9\ntimeCreated: 1651572748"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/Boolean Result\",\n        fileName = \"event_no_param_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamBoolResult : EventNoParamResult<bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5ab3fab12b464fde8a0870f50eb63227\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/Float Result\",\n        fileName = \"event_no_param_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamFloatResult : EventNoParamResult<float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6217d963db85402c9de627d2d8d69212\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/GameObject Result\",\n        fileName = \"event_no_param_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamGameObjectResult : EventNoParamResult<GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: eb1a45f1342d4b8f9d3168c9bd787880\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/Int Result\",\n        fileName = \"event_no_param_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamIntResult : EventNoParamResult<int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ef33b7c4a94e4d84a5c81533db50b708\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/Object Result\",\n        fileName = \"event_no_param_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamObjectResult : EventNoParamResult<object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 59709cd40f054a9c9e0318ac778c56b7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamResult.cs",
    "content": "using VirtueSky.Core;\nusing System;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    public class EventNoParamResult<TResult> : BaseSO, IEventNoParamResult<TResult>\n    {\n        private Func<TResult> onRaised = null;\n#if UNITY_EDITOR\n        [Space(10)] [ShowIf(nameof(ConditionShow))] [ReadOnly, SerializeField]\n        private TResult valueResult = default(TResult);\n\n        [ShowIf(nameof(ConditionShow))]\n        [Button(\"Raise\")]\n        private void DebugRaiseEvent()\n        {\n            valueResult = Raise();\n        }\n\n        private bool ConditionShow => EditorApplication.isPlaying;\n#endif\n        public TResult Raise()\n        {\n            TResult result = default;\n            if (!Application.isPlaying) return result;\n\n            if (onRaised != null) result = onRaised.Invoke();\n            return result;\n        }\n\n        public event Func<TResult> OnRaised\n        {\n            add { onRaised += value; }\n            remove { onRaised -= value; }\n        }\n\n        public void AddListener(Func<TResult> func)\n        {\n            onRaised += func;\n        }\n\n        public void RemoveListener(Func<TResult> func)\n        {\n            onRaised -= func;\n        }\n\n        public void RemoveAll()\n        {\n            onRaised = null;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 087399d034884472b66599ad570ef1ab\ntimeCreated: 1709281627"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/String Result\",\n        fileName = \"event_no_param_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamStringResult : EventNoParamResult<string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aa172e3ef72c460a979b54431c5307dd\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/Transform Result\",\n        fileName = \"event_no_param_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamTransformResult : EventNoParamResult<Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8aa6496b702641dca7fe9943e60e31d1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Event No Param/Vector3 Result\",\n        fileName = \"event_no_param_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class EventNoParamVector3Result : EventNoParamResult<Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result/EventNoParamVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8025d91ffb4749b58a33fbc7ff1a7e0e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 0fc74cd12a235ff478703747992aa8c7\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Event_NoParam.meta",
    "content": "fileFormatVersion: 2\nguid: 76a0de6e30e29514d8118075ea53f676\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/Bool Result\",\n        fileName = \"float_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventBoolResult : BaseEvent<float, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 12bac208a97648528a05f68f30ec190f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/Float Result\",\n        fileName = \"float_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventFloatResult : BaseEvent<float, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1faa3b967231461f96ad3ac3386e910b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/GameObject Result\",\n        fileName = \"float_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventGameObjectResult : BaseEvent<float, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d47105243ada4cfd914307a3f05e5b98\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/Int Result\",\n        fileName = \"float_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventIntResult : BaseEvent<float, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 217cda72cf4046a4bbeee23128931457\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/Object Result\",\n        fileName = \"float_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventObjectResult : BaseEvent<float, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e05693d26cf54fa4bc61bc181433dc66\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/String Result\",\n        fileName = \"float_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventStringResult : BaseEvent<float, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 54165a581dbd462396f0915a4c6e54b1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/Transform Result\",\n        fileName = \"float_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventTransformResult : BaseEvent<float, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9197e3ed49cf453e84a9f7f439d3b0c9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Float Event/Vector3 Result\",\n        fileName = \"float_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEventVector3Result : BaseEvent<float, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result/FloatEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b4cd59a658ee41ae9a3918a871002a00\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 3117c81f14224bf3954e93ea3d3a3a03\ntimeCreated: 1708747781"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/FloatEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Float Event\", fileName = \"float_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class FloatEvent : BaseEvent<float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/FloatEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0d8122074d0747c0bcac7e533000ff1e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/FloatEventListener.cs",
    "content": "using VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class FloatEventListener : BaseEventListener<float, FloatEvent, FloatEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/FloatEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 995103f2e8fb4e2b9b064c3d37181c3d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/FloatEventResponse.cs",
    "content": "using System;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class FloatEventResponse : BaseEventResponse<float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event/FloatEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 36073394bda540afb4697e351c927583\ntimeCreated: 1651591152"
  },
  {
    "path": "VirtueSky/Events/Runtime/Float_Event.meta",
    "content": "fileFormatVersion: 2\nguid: ce1d9882ec91f6549b34f8364a1c68d6\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/Bool Result\",\n        fileName = \"gameobject_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventBoolResult : BaseEvent<GameObject, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aa5eac033d974182bfd40eecb8ed40db\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/Float Result\",\n        fileName = \"gameobject_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventFloatResult : BaseEvent<GameObject, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 88fad7b13916467dae0ea470d7df09ec\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/GameObject Result\",\n        fileName = \"gameobject_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventGameObjectResult : BaseEvent<GameObject, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 39fdab98b5e544eab00258ec356e3b71\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/Int Result\",\n        fileName = \"gameobject_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventIntResult : BaseEvent<GameObject, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 463d35d96c6348289d8d3cfb93ce1f80\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/Object Result\",\n        fileName = \"gameobject_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventObjectResult : BaseEvent<GameObject, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 81803ee8ec044a39adb56ac9ecd645e0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/String Result\",\n        fileName = \"gameobject_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventStringResult : BaseEvent<GameObject, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2886a83a3d8e48e8b9d5329973d8e208\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/Transform Result\",\n        fileName = \"gameobject_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventTransformResult : BaseEvent<GameObject, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8443a4df0b22415bab5d62b8859db1da\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/GameObject Event/Vector3 Result\",\n        fileName = \"gameobject_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEventVector3Result : BaseEvent<GameObject, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result/GameObjectEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bd300e2220d84a23b8554d5fdae89945\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 7e5bb96bd8b44401ba76bae7d0ac3c13\ntimeCreated: 1715332844"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/GameObjectEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/GameObject Event\", fileName = \"gameobject_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class GameObjectEvent : BaseEvent<GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/GameObjectEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0a0508493bd04e4f92ca2a6213ac7808\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventListener.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    public class GameObjectEventListener : BaseEventListener<GameObject, GameObjectEvent, GameObjectEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 05c7e72deb6b46cea123beeb0401340f\ntimeCreated: 1715332800"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventResponse.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class GameObjectEventResponse : BaseEventResponse<GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event/GameObjectEventResponse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 503b99c887194fe6be55014bd73779fc\ntimeCreated: 1715332721"
  },
  {
    "path": "VirtueSky/Events/Runtime/GameObject_Event.meta",
    "content": "fileFormatVersion: 2\nguid: edc42b6d1574485f81087c5681e1cfa1\ntimeCreated: 1715332649"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/Bool Result\",\n        fileName = \"int_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventBoolResult : BaseEvent<int, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 57d4e884db124e22afc24630ed354828\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/Float Result\",\n        fileName = \"int_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventFloatResult : BaseEvent<int, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 00da8eff40dc476499c09b87b72c731c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/GameObject Result\",\n        fileName = \"int_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventGameObjectResult : BaseEvent<int, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a573493495504c8f9ca82108fb849c14\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/Int Result\",\n        fileName = \"int_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventIntResult : BaseEvent<int, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5a6d60d18a2b4c1eb9946177245d7896\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/Object Result\",\n        fileName = \"int_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventObjectResult : BaseEvent<int, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: beff6470bcbe4db08054837335070f24\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/String Result\",\n        fileName = \"int_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventStringResult : BaseEvent<int, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8696075c48f345259d1bde0bff5572bf\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/Transform Result\",\n        fileName = \"int_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventTransformResult : BaseEvent<int, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b0e76b8386d1406fa58b31cec5547cd4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Int Event/Vector3 Result\",\n        fileName = \"int_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntEventVector3Result : BaseEvent<int, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result/IntEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 421cda8aa71a4df8aa65abb8f0cc58ed\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 46b5110e766b4ae48a00f34d8a5f0254\ntimeCreated: 1708748301"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/IntegerEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Integer Event\", fileName = \"int_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class IntegerEvent : BaseEvent<int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/IntegerEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d6c2a70b0ee64462889213f36f37da24\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/IntegerEventListener.cs",
    "content": "using VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class IntegerEventListener : BaseEventListener<int, IntegerEvent, IntegerEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/IntegerEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 16935cb5c30543f0b25ff56d4717ccf7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/IntegerEventResponse.cs",
    "content": "using System;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class IntegerEventResponse : BaseEventResponse<int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event/IntegerEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 605bf97dd8cf41b1bd5be70b2a0c5c20\ntimeCreated: 1660313324"
  },
  {
    "path": "VirtueSky/Events/Runtime/Integer_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 386df31c69ee5984985306e9013805ff\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event/IEvent.cs",
    "content": "using System;\n\nnamespace VirtueSky.Events\n{\n    public interface IEvent\n    {\n        void Raise();\n        event Action OnRaised;\n        void AddListener(Action action);\n        void RemoveListener(Action action);\n        void AddListener(IEventListener listener);\n        void RemoveListener(IEventListener listener);\n        void RemoveAll();\n    }\n\n    public interface IEvent<T>\n    {\n        void Raise(T value);\n        event Action<T> OnRaised;\n        void AddListener(Action<T> action);\n        void RemoveListener(Action<T> action);\n        void AddListener(IEventListener<T> listener);\n        void RemoveListener(IEventListener<T> listener);\n        void RemoveAll();\n    }\n\n    public interface IEvent<T, TResult>\n    {\n        TResult Raise(T value);\n        event Func<T, TResult> OnRaised;\n        void AddListener(Func<T, TResult> func);\n        void RemoveListener(Func<T, TResult> func);\n        void AddListener(IEventListener<T, TResult> listener);\n        void RemoveListener(IEventListener<T, TResult> listener);\n        void RemoveAll();\n    }\n\n    public interface IEventNoParamResult<TResult>\n    {\n        TResult Raise();\n        void AddListener(Func<TResult> func);\n        void RemoveListener(Func<TResult> func);\n        void RemoveAll();\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event/IEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d2070d97c1045c34ea2aa99703681ff7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event/IEventListener.cs",
    "content": "using UnityEngine.Events;\n\nnamespace VirtueSky.Events\n{\n    public interface IEventListener\n    {\n        void OnEventRaised(BaseEvent eventRaise);\n    }\n\n    public interface IEventListener<TType>\n    {\n        void OnEventRaised(BaseEvent<TType> eventRaise, TType value);\n    }\n\n    public interface IEventListener<TType, TResult>\n    {\n        void OnEventRaised(BaseEvent<TType, TResult> eventRaise, TType value);\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event/IEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ea776ff2b47efba45aaaa97cd1d5b0e1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event/IEventResponse.cs",
    "content": "namespace VirtueSky.Events\n{\n    public interface IEventResponse\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event/IEventResponse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d75ca69d3baf1944e9fcc175757ee9e8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Interface_Event.meta",
    "content": "fileFormatVersion: 2\nguid: c2cb5329047646c58e7e78be8462d33f\ntimeCreated: 1697617947"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/Bool Result\",\n        fileName = \"object_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventBoolResult : BaseEvent<object, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 10e6362f6a294bcdacd0c07553658839\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/Float Result\",\n        fileName = \"object_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventFloatResult : BaseEvent<object, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 34ee83c58f53470a813e12dcbf0ed395\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/GameObject Result\",\n        fileName = \"object_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventGameObjectResult : BaseEvent<object, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2a52416d28b1492b929cf20d9d68d446\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/Int Result\",\n        fileName = \"object_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventIntResult : BaseEvent<object, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 650431f12c5f48048f25d88b3c177110\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/Object Result\",\n        fileName = \"object_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventObjectResult : BaseEvent<object, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e2db6b1dbecf4682aa45d1b9283d264f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/String Result\",\n        fileName = \"object_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventStringResult : BaseEvent<object, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0fdacef66d364fd7a04e8b228ccc77ed\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/Transform Result\",\n        fileName = \"object_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventTransformResult : BaseEvent<object, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 195e8386639d491a8cb5d5e4b6f84a1a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Object Event/Vector3 Result\",\n        fileName = \"object_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEventVector3Result : BaseEvent<object, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result/ObjectEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1747b009ef1942f3b43e1e64cf5afe54\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: dd046df497e54574bbe1a3f576b1fe9c\ntimeCreated: 1708748718"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/ObjectEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Object Event\", fileName = \"object_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ObjectEvent : BaseEvent<Object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/ObjectEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f13707fcbf06428493363549fe525368\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/ObjectEventListener.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class ObjectEventListener : BaseEventListener<Object, ObjectEvent, ObjectEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/ObjectEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6ff6677543cf4536a9f672e0851f915c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/ObjectEventResponse.cs",
    "content": "using System;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class ObjectEventResponse : BaseEventResponse<Object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event/ObjectEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ae05b91993734bc7b39f1dfe3e3c193e\ntimeCreated: 1651590963"
  },
  {
    "path": "VirtueSky/Events/Runtime/Object_Event.meta",
    "content": "fileFormatVersion: 2\nguid: ef0ee8801f226b04f8dc9bf1f5fd28b3\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEvent.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.DataType;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/ShortDouble Event\", fileName = \"short_double_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ShortDoubleEvent : BaseEvent<ShortDouble>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8a3f4bf948b3823458a288ee16eab4d9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventListener.cs",
    "content": "﻿using VirtueSky.DataType;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class ShortDoubleEventListener : BaseEventListener<ShortDouble, ShortDoubleEvent, ShortDoubleEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 14a9ac023339adc48b39823e57aaab78\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventResponse.cs",
    "content": "﻿using System;\nusing VirtueSky.DataType;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class ShortDoubleEventResponse : BaseEventResponse<ShortDouble>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event/ShortDoubleEventResponse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8a7944dec2527be48bb2003844a9428a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/ShortDouble_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 048b8abc246701d479a0e54fd0a270cd\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/Bool Result\",\n        fileName = \"string_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventBoolResult : BaseEvent<string, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 35d4ff22e06d4ab4a89a6b1f1decebb6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/Float Result\",\n        fileName = \"string_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventFloatResult : BaseEvent<string, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5d3802529d6a44a78187a8cdabda1805\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/GameObject Result\",\n        fileName = \"string_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventGameObjectResult : BaseEvent<string, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9e409ad769e543158b91f676b0d0720c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/Int Result\",\n        fileName = \"string_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventIntResult : BaseEvent<string, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ba0cb3c0aa146b9969b921f592ca101\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/Object Result\",\n        fileName = \"string_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventObjectResult : BaseEvent<string, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1b74e192b77948c2af058a6e3893f2e4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/String Result\",\n        fileName = \"string_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventStringResult : BaseEvent<string, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 267b034fcb9b4283acb260745c1d7920\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/Transform Result\",\n        fileName = \"string_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventTransformResult : BaseEvent<string, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 681369168fd64ea085fa9204a2ec6a93\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/String Event/Vector3 Result\",\n        fileName = \"string_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEventVector3Result : BaseEvent<string, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result/StringEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 615d08d70aaa44d5841d124c0b92b351\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: a14a9fe672404bd1bb8662de6d1f5512\ntimeCreated: 1708749207"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/StringEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/String Event\", fileName = \"string_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class StringEvent : BaseEvent<string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/StringEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7403481dc1f5472fb389d85c74090ef5\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/StringEventListener.cs",
    "content": "using VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class StringEventListener : BaseEventListener<string, StringEvent, StringEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/StringEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 73a48105b6a944a69fe24790d53bbbea\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/StringEventResponse.cs",
    "content": "using System;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class StringEventResponse : BaseEventResponse<string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event/StringEventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 5b8a085f69174a3c9beeef25bb05bfd7\ntimeCreated: 1660273903"
  },
  {
    "path": "VirtueSky/Events/Runtime/String_Event.meta",
    "content": "fileFormatVersion: 2\nguid: d2bd365da6fd3ba43b04361c4c248a0e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/Bool Result\",\n        fileName = \"transform_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventBoolResult : BaseEvent<Transform, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: facbc86c28b44c769b2b9324a5c79e49\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/Float Result\",\n        fileName = \"transform_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventFloatResult : BaseEvent<Transform, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 08f256c76831441db810c4fd37e6590d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/GameObject Result\",\n        fileName = \"transform_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventGameObjectResult : BaseEvent<Transform, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 48fd269b7e264de4bfe4b8b7d5f7d2f3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/Int Result\",\n        fileName = \"transform_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventIntResult : BaseEvent<Transform, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e0371cf3d5d649df853e4beeda1d9931\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/Object Result\",\n        fileName = \"transform_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventObjectResult : BaseEvent<Transform, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5fbaf3c7a936483ca5f48cfa82b9edb9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/String Result\",\n        fileName = \"transform_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventStringResult : BaseEvent<Transform, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1e50cf9550ac462286c3743afd086990\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/Transform Result\",\n        fileName = \"transform_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventTransformResult : BaseEvent<Transform, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5be5e83df28340bf8b9c4fbcb2e8ef7f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Transform Event/Vector3 Result\",\n        fileName = \"transform_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEventVector3Result : BaseEvent<Transform, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result/TransformEventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7f7e050901ff4e19b7e1735b1a513009\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 8e33c282fc5443aa808f6f3dcc6cdbbf\ntimeCreated: 1715331564"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/TransformEvent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Transform Event\", fileName = \"transform_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class TransformEvent : BaseEvent<Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/TransformEvent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: af3a6d4bf4904719a9cbc9b60cea28df\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/TransformEventListener.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    public class TransformEventListener : BaseEventListener<Transform, TransformEvent, TransformEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/TransformEventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 192621c184b4474faec0d2af15633658\ntimeCreated: 1715332518"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/TransformEventResponse.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class TransformEventResponse : BaseEventResponse<Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event/TransformEventResponse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 062600a2791448798d489dbe845ebec1\ntimeCreated: 1715332550"
  },
  {
    "path": "VirtueSky/Events/Runtime/Transform_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 915ab2d6bede4928ac2e951849b36c90\ntimeCreated: 1715331546"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event/Vector2Event.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Vector2 Event\", fileName = \"vector2_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector2Event : BaseEvent<Vector2>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event/Vector2Event.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2e5819862aa24b89befaf72f9abdb43a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event/Vector2EventListener.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class Vector2EventListener : BaseEventListener<Vector2, Vector2Event, Vector2EventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event/Vector2EventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b4b3354987d4441c9f741cff3f8b24f3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event/Vector2EventResponse.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class Vector2EventResponse : BaseEventResponse<Vector2>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event/Vector2EventResponse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ddb304bee5ca4681b3713b7c57c904f1\ntimeCreated: 1757604412"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector2_Event.meta",
    "content": "fileFormatVersion: 2\nguid: dded5e8cf8f94a078d77417a5e6f18e5\ntimeCreated: 1757604328"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventBoolResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/Bool Result\",\n        fileName = \"vector3_event_bool_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventBoolResult : BaseEvent<Vector3, bool>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventBoolResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2af53608ffba4530978d70a6f5ce42b5\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventFloatResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/Float Result\",\n        fileName = \"vector3_event_float_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventFloatResult : BaseEvent<Vector3, float>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventFloatResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8e1ff4b068344daa8f209370bb30bf9f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventGameObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/GameObject Result\",\n        fileName = \"vector3_event_gameobject_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventGameObjectResult : BaseEvent<Vector3, GameObject>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventGameObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 096f83d658df425d9f0414d1503a7753\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventIntResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/Int Result\",\n        fileName = \"vector3_event_int_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventIntResult : BaseEvent<Vector3, int>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventIntResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4ef805eba18f450c8edc4dc7d808f9d6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventObjectResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/Object Result\",\n        fileName = \"vector3_event_object_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventObjectResult : BaseEvent<Vector3, object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventObjectResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a24824336c6b49fbab7be100260b6f0f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventStringResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/String Result\",\n        fileName = \"vector3_event_string_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventStringResult : BaseEvent<Vector3, string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventStringResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c84454eedc8f4fe4b1aa3ffa6f2a190f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventTransformResult.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/Transform Result\",\n        fileName = \"vector3_event_transform_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventTransformResult : BaseEvent<Vector3, Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventTransformResult.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b1dffe3a46a54fb6bc240b1f98bf5d23\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventVector3Result.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event-Result/Vector3 Event/Vector3 Result\",\n        fileName = \"vector3_event_vector3_result\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3EventVector3Result : BaseEvent<Vector3, Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result/Vector3EventVector3Result.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 33d62a00e0d24e3b882b1a6f6530fb36\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Event_Result.meta",
    "content": "fileFormatVersion: 2\nguid: 2f6b57e5e1004a45b8c066ba4b1cdb4c\ntimeCreated: 1708763401"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Vector3Event.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Event/Vector3 Event\", fileName = \"vector3_event\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class Vector3Event : BaseEvent<Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Vector3Event.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6204d80d69a942eeae93eff39c44aa91\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Vector3EventListener.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Events\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class Vector3EventListener : BaseEventListener<Vector3, Vector3Event, Vector3EventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Vector3EventListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 287ec16a80e0470794dd652b0c2636c6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Vector3EventResponse.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Events\n{\n    [Serializable]\n    public class Vector3EventResponse : BaseEventResponse<Vector3>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event/Vector3EventResponse.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 12ffc18fb6764f89a9271e41a8e1e24e\ntimeCreated: 1660440731"
  },
  {
    "path": "VirtueSky/Events/Runtime/Vector3_Event.meta",
    "content": "fileFormatVersion: 2\nguid: 8f8affc2d416bcc4eb5e479d9c597184\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime/virtuesky.sunflower.event.asmdef",
    "content": "{\n  \"name\": \"Virtuesky.Sunflower.Event\",\n  \"rootNamespace\": \"\",\n  \"references\": [\n    \"GUID:acb3cac55c622ec459c8caadf707623a\",\n    \"GUID:540154dd0c5ed9a4dbbe695c402232fb\",\n    \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n    \"GUID:324caed91501a9c47a04ebfd87b68794\"\n  ],\n  \"includePlatforms\": [],\n  \"excludePlatforms\": [],\n  \"allowUnsafeCode\": false,\n  \"overrideReferences\": false,\n  \"precompiledReferences\": [],\n  \"autoReferenced\": true,\n  \"defineConstraints\": [],\n  \"versionDefines\": [],\n  \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Events/Runtime/virtuesky.sunflower.event.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: bd40169efe8642149b1d2b72ba4903ce\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 41a3943bba6261d428d164cf82b35d24\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Events.meta",
    "content": "fileFormatVersion: 2\nguid: 75f898c4077929444929383a64dde79b\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/CustomFolder.cs",
    "content": "using System.IO;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace Virtuesky.FolderIcon.Editor\n{\n    [InitializeOnLoad]\n    public class CustomFolder\n    {\n        static CustomFolder()\n        {\n            IconDictionaryCreator.BuildDictionary();\n            EditorApplication.projectWindowItemOnGUI -= DrawFolderIcon;\n            EditorApplication.projectWindowItemOnGUI += DrawFolderIcon;\n        }\n\n        static void DrawFolderIcon(string guid, Rect rect)\n        {\n            if (IconDictionaryCreator.folderIconSettings == null ||\n                !IconDictionaryCreator.folderIconSettings.enableFolderIcons) return;\n            var path = AssetDatabase.GUIDToAssetPath(guid);\n            if (path == \"\" ||\n                Event.current.type != EventType.Repaint ||\n                !File.GetAttributes(path).HasFlag(FileAttributes.Directory) ||\n                !IconDictionaryCreator.folderIconSettings.folderIconsDictionary.ContainsKey(Path.GetFileName(path)))\n            {\n                return;\n            }\n\n\n            Rect imageRect;\n\n            if (rect.height > 20)\n            {\n                imageRect = new Rect(rect.x - 1, rect.y - 1, rect.width + 2, rect.width + 2);\n            }\n            else if (rect.x > 20)\n            {\n                imageRect = new Rect(rect.x - 1, rect.y - 1, rect.height + 2, rect.height + 2);\n            }\n            else\n            {\n                imageRect = new Rect(rect.x + 2, rect.y - 1, rect.height + 2, rect.height + 2);\n            }\n\n            var texture = IconDictionaryCreator.folderIconSettings.folderIconsDictionary[Path.GetFileName(path)];\n\n            if (texture == null)\n            {\n                return;\n            }\n\n            GUI.DrawTexture(imageRect, texture);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/CustomFolder.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aac759806ab097f4c8e471a5f411afde\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/FolderIconSettings.cs",
    "content": "using UnityEngine;\nusing VirtueSky.DataType;\nusing VirtueSky.Inspector;\n\nnamespace Virtuesky.FolderIcon.Editor\n{\n    [HideMonoScript]\n    public class FolderIconSettings : ScriptableObject\n    {\n        public bool enableFolderIcons;\n        public bool enableAutoCustomIconsDefault;\n\n        [ShowIf(nameof(enableFolderIcons)), SerializeField]\n        internal DictionaryCustom<string, Texture2D> folderIconsDictionary;\n\n        public void ClearCache()\n        {\n            folderIconsDictionary.Clear();\n        }\n\n        public void OnValidate()\n        {\n            IconDictionaryCreator.BuildDictionary();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/FolderIconSettings.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a1924e497ac37414e91f1284e084dc52\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/IconDictionaryCreator.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace Virtuesky.FolderIcon.Editor\n{\n    public class IconDictionaryCreator : AssetPostprocessor\n    {\n        private const string AssetsPath = \"/VirtueSky/FolderIcon/Icons\";\n        internal static FolderIconSettings folderIconSettings;\n\n        private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets,\n            string[] movedAssets, string[] movedFromAssetPaths)\n        {\n            if (!ContainsIconAsset(importedAssets) &&\n                !ContainsIconAsset(deletedAssets) &&\n                !ContainsIconAsset(movedAssets) &&\n                !ContainsIconAsset(movedFromAssetPaths))\n            {\n                return;\n            }\n\n            BuildDictionary();\n        }\n\n        private static bool ContainsIconAsset(string[] assets)\n        {\n            foreach (string str in assets)\n            {\n                if (ReplaceSeparatorChar(Path.GetDirectoryName(str)) ==\n                    FileExtension.GetPathFileInCurrentEnvironment(AssetsPath))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static string ReplaceSeparatorChar(string path)\n        {\n            return path.Replace(\"\\\\\", \"/\");\n        }\n\n        internal static void BuildDictionary()\n        {\n            if (folderIconSettings == null)\n            {\n                folderIconSettings = CreateAsset.GetScriptableAsset<FolderIconSettings>();\n            }\n\n\n            if (folderIconSettings != null && folderIconSettings.enableFolderIcons &&\n                folderIconSettings.enableAutoCustomIconsDefault)\n            {\n                var dir = new DirectoryInfo(FileExtension.GetPathFolderInCurrentEnvironment(AssetsPath));\n                FileInfo[] info = dir.GetFiles(\"*.png\");\n                foreach (FileInfo f in info)\n                {\n                    var texture =\n                        (Texture)AssetDatabase.LoadAssetAtPath(\n                            FileExtension.GetPathFileInCurrentEnvironment($\"{AssetsPath}/{f.Name}\"),\n                            typeof(Texture2D));\n                    if (texture == null) continue;\n                    if (!folderIconSettings.folderIconsDictionary.ContainsKey(Path.GetFileNameWithoutExtension(f.Name)))\n                    {\n                        folderIconSettings.folderIconsDictionary.Add(Path.GetFileNameWithoutExtension(f.Name), texture);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/IconDictionaryCreator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0a77cadbfb2c5454abdf50f2e809e1d9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/PackageIcon/icon_folder.unitypackage.meta",
    "content": "fileFormatVersion: 2\nguid: ae8c4eb046f1efe4b8dbd578ca128018\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/PackageIcon.meta",
    "content": "fileFormatVersion: 2\nguid: f515472d9efe0674c91f86231d70be03\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/Virtuesky.Sunflower.FolderIcon.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.FolderIcon\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:540154dd0c5ed9a4dbbe695c402232fb\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor/Virtuesky.Sunflower.FolderIcon.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 877be62fd20bbdb489dd86ee21cee87d\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 5e07d2c79a238874ba65d2d3c28e9932\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Animations.png.meta",
    "content": "fileFormatVersion: 2\nguid: eab75b706f70aca43b8ff64634c515ee\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Audio.png.meta",
    "content": "fileFormatVersion: 2\nguid: 30b6f094fe545f640b5f5da798a13fb8\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Default/Default.png.meta",
    "content": "fileFormatVersion: 2\nguid: 528e0cfe91970b64f9bf00466d825ed5\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Default.meta",
    "content": "fileFormatVersion: 2\nguid: 8b577a1a895ebf649a74109c56ad6871\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Editor.png.meta",
    "content": "fileFormatVersion: 2\nguid: 512d76f3dccd6f640b4ccc01cb61b756\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Fonts.png.meta",
    "content": "fileFormatVersion: 2\nguid: 62ddbe7c7b650f349b033ff9fd3d0bff\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Materials.png.meta",
    "content": "fileFormatVersion: 2\nguid: 89dbba36a0719d24f9287029f9ee6587\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Models.png.meta",
    "content": "fileFormatVersion: 2\nguid: 45ff670f2cb66164a8d6e10605691373\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Plugins.png.meta",
    "content": "fileFormatVersion: 2\nguid: 13b91f0a2558c7048ad52ab46cbec5d9\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Prefabs.png.meta",
    "content": "fileFormatVersion: 2\nguid: bb321d21ec6df16479b3b7ca2912c9c7\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Presets.png.meta",
    "content": "fileFormatVersion: 2\nguid: 78eeb920cc73f444b874a012016e0aba\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Resources.png.meta",
    "content": "fileFormatVersion: 2\nguid: 9100ae07f3844b644a425dc2faa495b8\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Scenes.png.meta",
    "content": "fileFormatVersion: 2\nguid: e883a49e0791ffb4da111b699600a550\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Scripts.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6e5375f7dc7dd98459edcd2fb9a3f8b5\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Settings.png.meta",
    "content": "fileFormatVersion: 2\nguid: 3eeb12e1542f9da42815f009b4d9f05d\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Shaders.png.meta",
    "content": "fileFormatVersion: 2\nguid: 2bc839d7e3db2bf478572af026c7b8b4\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Sprites.png.meta",
    "content": "fileFormatVersion: 2\nguid: b37da4319a2a50d4ebe3cc38697d9acf\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons/Textures.png.meta",
    "content": "fileFormatVersion: 2\nguid: cb4c49e67fb74904287e1799e8b3e47b\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 1\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 1\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: WebGL\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 256\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 2\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon/Icons.meta",
    "content": "fileFormatVersion: 2\nguid: c1c3939351ff68442b9ebde71b3785b0\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/FolderIcon.meta",
    "content": "fileFormatVersion: 2\nguid: e6b635d8cabe36a4384e73ea1b711728\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/GameService/Runtime/AppleAuthentication.cs",
    "content": "using System.Text;\nusing UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\nusing VirtueSky.Variables;\n\n#if UNITY_IOS && VIRTUESKY_APPLE_AUTH\nusing AppleAuth;\nusing AppleAuth.Enums;\nusing AppleAuth.Extensions;\nusing AppleAuth.Interfaces;\nusing AppleAuth.Native;\n\n#endif\n\n\nnamespace VirtueSky.GameService\n{\n    [EditorIcon(\"icon_authentication\")]\n    public class AppleAuthentication : ServiceAuthentication\n    {\n        [SerializeField] private StringVariable authorizationCodeVariable;\n        [SerializeField] private StringVariable userIdVariable;\n        [SerializeField] private EventNoParam tryLoginEvent;\n\n#if UNITY_IOS && VIRTUESKY_APPLE_AUTH\n        private IAppleAuthManager _iAppleAuthManager;\n#endif\n\n\n        protected override void Init()\n        {\n#if UNITY_IOS && VIRTUESKY_APPLE_AUTH\n            serverCode.Value = \"\";\n            authorizationCodeVariable.Value = \"\";\n            status.SetNotLoggedIn();\n            if (AppleAuthManager.IsCurrentPlatformSupported)\n            {\n                // Creates a default JSON deserializer, to transform JSON Native responses to C# instances\n                var deserializer = new PayloadDeserializer();\n                // Creates an Apple Authentication manager with the deserializer\n                this._iAppleAuthManager = new AppleAuthManager(deserializer);\n                loginEvent.AddListener(Login);\n                tryLoginEvent.AddListener(TryLogin);\n            }\n#endif\n        }\n\n        private void Update()\n        {\n#if UNITY_IOS && VIRTUESKY_APPLE_AUTH\n            // Updates the AppleAuthManager instance to execute\n            // pending callbacks inside Unity's execution loop\n            if (this._iAppleAuthManager != null)\n            {\n                this._iAppleAuthManager.Update();\n            }\n#endif\n        }\n\n        protected override void Login()\n        {\n#if UNITY_IOS && VIRTUESKY_APPLE_AUTH\n            var loginArgs =\n                new AppleAuthLoginArgs(LoginOptions.IncludeEmail | LoginOptions.IncludeFullName);\n\n            this._iAppleAuthManager.LoginWithAppleId(\n                loginArgs,\n                credential =>\n                {\n                    // Obtained credential, cast it to IAppleIDCredential\n                    if (credential is IAppleIDCredential appleIdCredential)\n                    {\n                        // Apple User ID\n                        // You should save the user ID somewhere in the device\n                        var userId = appleIdCredential.User;\n\n                        // Email (Received ONLY in the first login)\n                        var email = appleIdCredential.Email;\n\n                        // Full name (Received ONLY in the first login)\n                        var fullName = appleIdCredential.FullName;\n\n                        // Identity token\n                        var identityToken = Encoding.UTF8.GetString(\n                            appleIdCredential.IdentityToken,\n                            0,\n                            appleIdCredential.IdentityToken.Length);\n\n                        // Authorization code\n                        var authorizationCode = Encoding.UTF8.GetString(\n                            appleIdCredential.AuthorizationCode,\n                            0,\n                            appleIdCredential.AuthorizationCode.Length);\n\n                        // And now you have all the information to create/login a user in your system\n                        serverCode.Value = identityToken;\n                        authorizationCodeVariable.Value = authorizationCode;\n                        userIdVariable.Value = userId;\n                        nameVariable.Value = $\"{fullName.GivenName} {fullName.FamilyName}\";\n                        status.SetSuccessful();\n                    }\n                    else\n                    {\n                        serverCode.Value = \"\";\n                        userIdVariable.Value = \"\";\n                        status.SetFailed();\n                    }\n                },\n                error =>\n                {\n                    // Something went wrong\n                    var authorizationErrorCode = error.GetAuthorizationErrorCode();\n                    status.SetFailed();\n                });\n#endif\n        }\n\n        /// <summary>\n        /// Login when Apple credential still valid.\n        /// </summary>\n        private void TryLogin()\n        {\n#if UNITY_IOS && VIRTUESKY_APPLE_AUTH\n            if (string.IsNullOrEmpty(userIdVariable.Value)) return;\n            this._iAppleAuthManager.GetCredentialState(userIdVariable.Value, state =>\n            {\n                switch (state)\n                {\n                    case CredentialState.Revoked:\n                        break;\n                    case CredentialState.Authorized:\n                        Debug.Log($\"Apple credential still valid. Auto-login with userId: {userIdVariable.Value}\");\n                        Login();\n                        break;\n                    case CredentialState.NotFound:\n                        Debug.LogWarning(\"Apple credential invalid or revoked.\");\n                        userIdVariable.Value = \"\";\n                        break;\n                    case CredentialState.Transferred:\n                        break;\n                }\n            }, error => { Debug.LogError(\"CredentialState check failed: \" + error.ToString()); });\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/GameService/Runtime/AppleAuthentication.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f59cb8f4b8592824aa250e0ed64dfe29\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: e6bde4f6f44782647a9e30445fb10b74, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/GameService/Runtime/GooglePlayGamesAuthentication.cs",
    "content": "#if UNITY_ANDROID && VIRTUESKY_GPGS\nusing GooglePlayGames;\nusing GooglePlayGames.BasicApi;\n#endif\n\nusing System.Threading.Tasks;\nusing UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.GameService\n{\n    [EditorIcon(\"icon_authentication\")]\n    public class GooglePlayGamesAuthentication : ServiceAuthentication\n    {\n        [SerializeField] private EventNoParam getNewServerCodeEvent;\n\n        protected override void Init()\n        {\n#if UNITY_ANDROID && VIRTUESKY_GPGS\n            serverCode.Value = \"\";\n            status.SetNotLoggedIn();\n            PlayGamesPlatform.Activate();\n            loginEvent.AddListener(Login);\n            getNewServerCodeEvent.AddListener(OnGetNewServerCode);\n#endif\n        }\n#if UNITY_ANDROID && VIRTUESKY_GPGS\n        private async void OnGetNewServerCode()\n        {\n            if (!PlayGamesPlatform.Instance.IsAuthenticated()) return;\n            (serverCode.Value, status.Value) = await GetNewServerCode();\n        }\n\n        private Task<(string, StatusLogin)> GetNewServerCode()\n        {\n            var taskSource = new TaskCompletionSource<(string, StatusLogin)>();\n\n            PlayGamesPlatform.Instance.RequestServerSideAccess(true,\n                code => taskSource.SetResult((code, StatusLogin.Successful)));\n            return taskSource.Task;\n        }\n#endif\n        protected override void Login()\n        {\n#if UNITY_ANDROID && VIRTUESKY_GPGS\n            PlayGamesPlatform.Instance.Authenticate((success) =>\n            {\n                if (success == SignInStatus.Success)\n                {\n                    Debug.Log(\"Login with Google Play games successful.\");\n                    PlayGamesPlatform.Instance.RequestServerSideAccess(true,\n                        code =>\n                        {\n                            Debug.Log(\"Authorization code: \" + code);\n                            serverCode.Value = code;\n                            nameVariable.Value = PlayGamesPlatform.Instance.GetUserDisplayName();\n                            status.SetSuccessful();\n                        });\n                }\n                else\n                {\n                    PlayGamesPlatform.Instance.ManuallyAuthenticate(success =>\n                    {\n                        if (success == SignInStatus.Success)\n                        {\n                            PlayGamesPlatform.Instance.RequestServerSideAccess(true,\n                                code =>\n                                {\n                                    Debug.Log(\"Authorization code: \" + code);\n                                    serverCode.Value = code;\n                                    nameVariable.Value = PlayGamesPlatform.Instance.GetUserDisplayName();\n                                    status.SetSuccessful();\n                                });\n                        }\n                        else\n                        {\n                            Debug.Log(\"Login Failed\");\n                            serverCode.Value = \"\";\n                            status.SetFailed();\n                        }\n                    });\n                }\n            });\n#endif\n        }\n\n        public static bool IsSignIn()\n        {\n#if UNITY_ANDROID && VIRTUESKY_GPGS\n            return PlayGamesPlatform.Instance.IsAuthenticated();\n\n#else\n            return false;\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/GameService/Runtime/GooglePlayGamesAuthentication.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 49195c8970f14421b92361f977eca22d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: e6bde4f6f44782647a9e30445fb10b74, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/GameService/Runtime/ServiceAuthentication.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Variables;\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\n\nnamespace VirtueSky.GameService\n{\n    public abstract class ServiceAuthentication : MonoBehaviour\n    {\n        [SerializeField] private bool dontDestroyOnLoad;\n        [SerializeField] protected StatusLoginVariable status;\n        [SerializeField] protected StringVariable serverCode;\n        [SerializeField] protected StringVariable nameVariable;\n        [SerializeField] protected EventNoParam loginEvent;\n\n        protected virtual void Awake()\n        {\n            if (dontDestroyOnLoad)\n            {\n                DontDestroyOnLoad(gameObject);\n            }\n        }\n\n        private void Start()\n        {\n            Init();\n        }\n\n        protected abstract void Init();\n        protected abstract void Login();\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            status = CreateAsset.CreateAndGetScriptableAsset<StatusLoginVariable>(\"/GameService\",\n                \"status_login_variables\");\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/GameService/Runtime/ServiceAuthentication.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f499843dccf345548b7dd3e954d94ffe\ntimeCreated: 1722237144"
  },
  {
    "path": "VirtueSky/GameService/Runtime/Variable/StatusLoginVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.GameService\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Game Service/Status Login Variable\",\n        fileName = \"status_login_variables\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class StatusLoginVariable : BaseVariable<StatusLogin>\n    {\n        public void SetNotLoggedIn()\n        {\n            Value = StatusLogin.NotLoggedIn;\n        }\n\n        public void SetSuccessful()\n        {\n            Value = StatusLogin.Successful;\n        }\n\n        public void SetFailed()\n        {\n            Value = StatusLogin.Failed;\n        }\n    }\n\n    public enum StatusLogin\n    {\n        NotLoggedIn,\n        Successful,\n        Failed\n    }\n}"
  },
  {
    "path": "VirtueSky/GameService/Runtime/Variable/StatusLoginVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 63fab0e810474ad9bd48cc760d1311b2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/GameService/Runtime/Variable.meta",
    "content": "fileFormatVersion: 2\nguid: bd3fa253ca6846bab2521d35555ff162\ntimeCreated: 1722240964"
  },
  {
    "path": "VirtueSky/GameService/Runtime/Virtuesky.Sunflower.GameService.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.GameService\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:1ed07ff861e5f468287b0baef844706d\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:e2146bdc04d424169b039613a1b62bdf\",\n        \"GUID:35d694408290717499b3838802212c7f\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/GameService/Runtime/Virtuesky.Sunflower.GameService.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 2356c024261911440b11bc0bf55f4d5d\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/GameService/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: d7d242c8225bfc94cbb90a295f94c806\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/GameService.meta",
    "content": "fileFormatVersion: 2\nguid: 0dfa84c557cc1d24ea633af32cdb75cc\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Attribute/HierarchyNullable.asmdef",
    "content": "{\n    \"name\": \"HierarchyNullable\",\n    \"rootNamespace\": \"\",\n    \"references\": [],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Attribute/HierarchyNullable.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 784c1df74834cb743a426a6126f1064d\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Attribute/HierarchyNullable.cs",
    "content": "using UnityEngine;\n\npublic class HierarchyNullableAttribute : PropertyAttribute\n{\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Attribute/HierarchyNullable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 15892d7337a046e43b2c6bad21242c1a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Attribute.meta",
    "content": "fileFormatVersion: 2\nguid: 602672b16b2911c47892de4f436d5894\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/HierarchyEditor.asmdef",
    "content": "{\n    \"name\": \"HierarchyEditor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"Virtuesky.Sunflower.DataStorage.Editor\",\n        \"VirtueSky.Sunflower.Inspector\",\n        \"HierarchyNullable\",\n        \"HierarchyRuntime\",\n        \"Virtuesky.Sunflower.UtilsEdtitor\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/HierarchyEditor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 49674d15b25185649b7ec8ac5d378747\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/Base/BaseComponent.cs",
    "content": "using UnityEngine;\nusing System;\nusing System.Collections.Generic;\nusing VirtueSky.Hierarchy;\n\nnamespace VirtueSky.Hierarchy.HComponent.Base\n{\n    public enum LayoutStatus\n    {\n        Success,\n        Partly,\n        Failed,\n    }\n\n    public class BaseComponent\n    {\n        // PUBLIC\n        public Rect rect = new Rect(0, 0, 16, 16);\n\n        // PRIVATE\n        protected bool enabled = false;\n        protected bool showComponentDuringPlayMode = false;\n\n        // CONSTRUCTOR\n        public BaseComponent()\n        {\n        }\n\n        // PUBLIC\n        public virtual LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            return LayoutStatus.Success;\n        }\n\n        public virtual void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n\n        }\n\n        public virtual void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n\n        }\n\n        public virtual void disabledHandler(GameObject gameObject, ObjectList objectList)\n        {\n\n        }\n\n        public virtual void setEnabled(bool value)\n        {\n            this.enabled = value;\n        }       \n\n        public virtual bool isEnabled()\n        {\n            if (!enabled) \n            {\n                return false;\n            }\n            else \n            {\n                if (Application.isPlaying) return showComponentDuringPlayMode;            \n                else return true;\n            }\n        }\n\n        // PROTECTED\n        protected void getGameObjectListRecursive(GameObject gameObject, ref List<GameObject>result, int maxDepth = int.MaxValue)\n        {\n            result.Add(gameObject);\n            if (maxDepth > 0)\n            {\n                Transform transform = gameObject.transform;\n                for (int i = transform.childCount - 1; i >= 0; i--)      \n                    getGameObjectListRecursive(transform.GetChild(i).gameObject, ref result, maxDepth - 1);     \n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/Base/BaseComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0276e09a5dfa026458af52fb4ee838d2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/Base.meta",
    "content": "fileFormatVersion: 2\nguid: bf7b2f59a50ea694b898adc34d520d86\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ChildrenCountComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class ChildrenCountComponent: BaseComponent \n    {\n        // PRIVATE\n        private GUIStyle labelStyle;\n\n        // CONSTRUCTOR\n        public ChildrenCountComponent ()\n        {\n            labelStyle = new GUIStyle();\n            labelStyle.fontSize = 9;\n            labelStyle.clipping = TextClipping.Clip;  \n            labelStyle.alignment = TextAnchor.MiddleRight;\n\n            rect.width = 22;\n            rect.height = 16;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountLabelSize         , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ChildrenCountLabelColor        , settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled = HierarchySettings.getInstance().get<bool>(HierarchySetting.ChildrenCountShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.ChildrenCountShowDuringPlayMode);\n            HierarchySize labelSize = (HierarchySize)HierarchySettings.getInstance().get<int>(HierarchySetting.ChildrenCountLabelSize);\n            labelStyle.normal.textColor = HierarchySettings.getInstance().getColor(HierarchySetting.ChildrenCountLabelColor);\n            labelStyle.fontSize = labelSize == HierarchySize.Normal ? 8 : 9;\n            rect.width = labelSize == HierarchySize.Normal ? 17 : 22;\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < rect.width)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= rect.width + 2;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                rect.y += (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n                rect.height = EditorGUIUtility.singleLineHeight;\n                return LayoutStatus.Success;\n            }\n        }\n        \n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {  \n            int childrenCount = gameObject.transform.childCount;\n            if (childrenCount > 0) GUI.Label(rect, childrenCount.ToString(), labelStyle);\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ChildrenCountComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2f1b06ed245a831438a2f155f068dd8a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ColorComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class ColorComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color inactiveColor;\n        private Texture2D colorTexture;\n        private Rect colorRect = new Rect();\n\n        // CONSTRUCTOR\n        public ColorComponent()\n        {\n            colorTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyColorButton);\n\n            rect.width = 8;\n            rect.height = 16;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ColorShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ColorShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor, settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.ColorShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.ColorShowDuringPlayMode);\n            inactiveColor               = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n        }\n\n        // LAYOUT\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 8)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 8;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                return LayoutStatus.Success;\n            }\n        }\n\n        // DRAW\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            if (objectList != null)\n            {\n                Color newColor;\n                if (objectList.gameObjectColor.TryGetValue(gameObject, out newColor))\n                {\n                    colorRect.Set(rect.x + 1, rect.y + 1, 5, rect.height - 1);\n                    EditorGUI.DrawRect(colorRect, newColor);\n                    return;\n                }\n            }\n\n            HierarchyColorUtils.setColor(inactiveColor);\n            GUI.DrawTexture(rect, colorTexture, ScaleMode.StretchToFill, true, 1);\n            HierarchyColorUtils.clearColor();\n        }\n\n        // EVENTS\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition))\n            {\n                if (currentEvent.type == EventType.MouseDown)\n                {\n                    try {\n                        PopupWindow.Show(rect, new HierarchyColorPickerWindow(Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject }, colorSelectedHandler, colorRemovedHandler));\n                    } \n                    catch {}\n                }\n                currentEvent.Use();\n            }\n        }\n\n        // PRIVATE\n        private void colorSelectedHandler(GameObject[] gameObjects, Color color)\n        {\n            for (int i = gameObjects.Length - 1; i >= 0; i--)\n            {\n                GameObject gameObject = gameObjects[i];\n                ObjectList objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[i], true);\n                Undo.RecordObject(objectList, \"Color Changed\");\n                if (objectList.gameObjectColor.ContainsKey(gameObject))\n                {\n                    objectList.gameObjectColor[gameObject] = color;\n                }\n                else\n                {\n                    objectList.gameObjectColor.Add(gameObject, color);\n                }                \n            }\n            EditorApplication.RepaintHierarchyWindow();\n        }\n\n        private void colorRemovedHandler(GameObject[] gameObjects)\n        {\n            for (int i = gameObjects.Length - 1; i >= 0; i--)\n            {\n                GameObject gameObject = gameObjects[i];\n                ObjectList objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[i], true);\n                if (objectList.gameObjectColor.ContainsKey(gameObject))                \n                {\n                    Undo.RecordObject(objectList, \"Color Changed\");\n                    objectList.gameObjectColor.Remove(gameObject);                          \n                }\n            }\n            EditorApplication.RepaintHierarchyWindow();\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ColorComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 335f808a233353e49826c77694c5a31c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ComponentsComponent.cs",
    "content": "using System;\nusing System.Reflection;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class ComponentsComponent: BaseComponent\n    {\n        // PRIVATE\n        private GUIStyle hintLabelStyle;\n        private Color grayColor;\n        private Color backgroundDarkColor;\n        private Texture2D componentIcon;\n        private List<Component> components = new List<Component>();   \n        private Rect eventRect = new Rect(0, 0, 16, 16);\n        private int componentsToDraw;\n        private List<string> ignoreScripts;\n\n        // CONSTRUCTOR\n        public ComponentsComponent ()\n        {\n            this.backgroundDarkColor = HierarchyResources.getInstance().getColor(HierarchyColor.BackgroundDark);\n            this.grayColor           = HierarchyResources.getInstance().getColor(HierarchyColor.Gray);\n            this.componentIcon       = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyComponentUnknownIcon);\n\n            hintLabelStyle = new GUIStyle();\n            hintLabelStyle.normal.textColor = grayColor;\n            hintLabelStyle.fontSize = 11;\n            hintLabelStyle.clipping = TextClipping.Clip;  \n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsIconSize          , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsIgnore            , settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.ComponentsShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.ComponentsShowDuringPlayMode);\n            HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get<int>(HierarchySetting.ComponentsIconSize);\n            rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13));       \n\n            string ignoreString = HierarchySettings.getInstance().get<string>(HierarchySetting.ComponentsIgnore);\n            if (ignoreString != \"\") \n            {\n                ignoreScripts = new List<string>(ignoreString.Split(new char[] { ',', ';', '.', ' ' }));\n                ignoreScripts.RemoveAll(item => item == \"\");\n            }\n            else ignoreScripts = null;\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            Component[] currentComponents = gameObject.GetComponents<Component>();\n\n            components.Clear();\n            if (ignoreScripts != null)\n            {\n                for (int i = 0; i < currentComponents.Length; i++)\n                {\n                    string componentName = currentComponents[i].GetType().FullName;\n                    bool ignore = false;\n                    for (int j = ignoreScripts.Count - 1; j >= 0; j--)\n                    {\n                        if (componentName.Contains(ignoreScripts[j]))\n                        {\n                            ignore = true;\n                            break;\n                        } \n                    }\n                    if (!ignore) components.Add(currentComponents[i]);\n                }\n            }\n            else\n            {\n                components.AddRange(currentComponents);\n            }\n\n            int maxComponentsCount = Mathf.FloorToInt((maxWidth - 2) / rect.width);\n            componentsToDraw = Math.Min(maxComponentsCount, components.Count - 1);\n\n            float totalWidth = 2 + rect.width * componentsToDraw;\n    \n            curRect.x -= totalWidth;\n\n            rect.x = curRect.x;\n            rect.y = curRect.y - (rect.height - 16) / 2;\n\n            eventRect.width = totalWidth;\n            eventRect.x = rect.x;\n            eventRect.y = rect.y;\n\n            if (maxComponentsCount >= components.Count - 1) return LayoutStatus.Success;\n            else if (maxComponentsCount == 0) return LayoutStatus.Failed;\n            else return LayoutStatus.Partly;\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            for (int i = components.Count - componentsToDraw, n = components.Count; i < n; i++)\n            {\n                Component component = components[i];\n                if (component is Transform) continue;\n                                \n                GUIContent content = EditorGUIUtility.ObjectContent(component, null);\n\n                bool enabled = true;\n                try\n                {\n                    PropertyInfo propertyInfo = component.GetType().GetProperty(\"enabled\");\n                    enabled = (bool)propertyInfo.GetGetMethod().Invoke(component, null);\n                }\n                catch {}\n\n                Color color = GUI.color;\n                color.a = enabled ? 1f : 0.3f;\n                GUI.color = color;\n                GUI.DrawTexture(rect, content.image == null ? componentIcon : content.image, ScaleMode.ScaleToFit);\n                color.a = 1;\n                GUI.color = color;\n\n                if (rect.Contains(Event.current.mousePosition))\n                {        \n                    string componentName = \"Missing script\";\n                    if (component != null) componentName = component.GetType().Name;\n\n                    int labelWidth = Mathf.CeilToInt(hintLabelStyle.CalcSize(new GUIContent(componentName)).x);                    \n                    selectionRect.x = rect.x - labelWidth / 2 - 4;\n                    selectionRect.width = labelWidth + 8;\n                    selectionRect.height -= 1;\n\n                    if (selectionRect.y > 16) selectionRect.y -= 16;\n                    else selectionRect.x += labelWidth / 2 + 18;\n\n                    EditorGUI.DrawRect(selectionRect, backgroundDarkColor);\n                    selectionRect.x += 4;\n                    selectionRect.y += (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n                    selectionRect.height = EditorGUIUtility.singleLineHeight;\n\n                    EditorGUI.LabelField(selectionRect, componentName, hintLabelStyle);\n                }\n\n                rect.x += rect.width;\n            }\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.button == 0 && eventRect.Contains(currentEvent.mousePosition))\n            {\n                if (currentEvent.type == EventType.MouseDown)\n                {\n                    int id = Mathf.FloorToInt((currentEvent.mousePosition.x - eventRect.x) / rect.width) + components.Count - 1 - componentsToDraw + 1;\n\n                    try\n                    {\n                        PropertyInfo propertyInfo = components[id].GetType().GetProperty(\"enabled\");\n                        bool enabled = (bool)propertyInfo.GetGetMethod().Invoke(components[id], null);\n                        Undo.RecordObject(components[id], enabled ? \"Disable Component\" : \"Enable Component\");\n                        propertyInfo.GetSetMethod().Invoke(components[id], new object[] { !enabled });\n                    }\n                    catch {}\n\n                    EditorUtility.SetDirty(gameObject);\n                }\n                currentEvent.Use();\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ComponentsComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b711e39572aded64d92872ed8343ffb3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ErrorComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing UnityEngine.Events;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\nusing System.Reflection;\nusing System.Collections;\nusing UnityEditorInternal;\nusing System.Text;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class ErrorComponent : BaseComponent\n    {\n        // PRIVATE\n        private Color activeColor;\n        private Color inactiveColor;\n        private Texture2D errorIconTexture;\n        private bool showErrorOfChildren;\n        private bool showErrorTypeReferenceIsNull;\n        private bool showErrorTypeReferenceIsMissing;\n        private bool showErrorTypeStringIsEmpty;\n        private bool showErrorIconScriptIsMissing;\n        private bool showErrorIconWhenTagIsUndefined;\n        private bool showErrorForDisabledComponents;\n        private bool showErrorIconMissingEventMethod;\n        private bool showErrorForDisabledGameObjects;\n        private List<string> ignoreErrorOfMonoBehaviours;\n        private StringBuilder errorStringBuilder;\n        private int errorCount;\n\n        // CONSTRUCTOR\n        public ErrorComponent()\n        {\n            rect.width = 7;\n\n            errorIconTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyErrorIcon);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowIconOnParent, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowReferenceIsNull, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowReferenceIsMissing, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowStringIsEmpty, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowScriptIsMissing, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowForDisabledComponents, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowForDisabledGameObjects, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowMissingEventMethod, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShow, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ErrorIgnoreString, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor, settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            showErrorOfChildren = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowIconOnParent);\n            showErrorTypeReferenceIsNull = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowReferenceIsNull);\n            showErrorTypeReferenceIsMissing = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowReferenceIsMissing);\n            showErrorTypeStringIsEmpty = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowStringIsEmpty);\n            showErrorIconScriptIsMissing = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowScriptIsMissing);\n            showErrorForDisabledComponents = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowForDisabledComponents);\n            showErrorForDisabledGameObjects =\n                HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowForDisabledGameObjects);\n            showErrorIconMissingEventMethod = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowMissingEventMethod);\n            showErrorIconWhenTagIsUndefined =\n                HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined);\n            activeColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor);\n            inactiveColor = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n            enabled = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.ErrorShowDuringPlayMode);\n\n            string ignoreErrorOfMonoBehavioursString = HierarchySettings.getInstance().get<string>(HierarchySetting.ErrorIgnoreString);\n            if (ignoreErrorOfMonoBehavioursString != \"\")\n            {\n                ignoreErrorOfMonoBehaviours =\n                    new List<string>(ignoreErrorOfMonoBehavioursString.Split(new char[] { ',', ';', '.', ' ' }));\n                ignoreErrorOfMonoBehaviours.RemoveAll(item => item == \"\");\n            }\n            else ignoreErrorOfMonoBehaviours = null;\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect,\n            ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 7)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 7;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            bool errorFound = findError(gameObject, gameObject.GetComponents<MonoBehaviour>());\n\n            if (errorFound)\n            {\n                HierarchyColorUtils.setColor(activeColor);\n                GUI.DrawTexture(rect, errorIconTexture);\n                HierarchyColorUtils.clearColor();\n            }\n            else if (showErrorOfChildren)\n            {\n                errorFound = findError(gameObject, gameObject.GetComponentsInChildren<MonoBehaviour>(true));\n                if (errorFound)\n                {\n                    HierarchyColorUtils.setColor(inactiveColor);\n                    GUI.DrawTexture(rect, errorIconTexture);\n                    HierarchyColorUtils.clearColor();\n                }\n            }\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 &&\n                rect.Contains(currentEvent.mousePosition))\n            {\n                currentEvent.Use();\n\n                errorCount = 0;\n                errorStringBuilder = new StringBuilder();\n                findError(gameObject, gameObject.GetComponents<MonoBehaviour>(), true);\n\n                if (errorCount > 0)\n                {\n                    EditorUtility.DisplayDialog(\n                        errorCount + (errorCount == 1 ? \" error was found\" : \" errors were found\"),\n                        errorStringBuilder.ToString(), \"OK\");\n                }\n            }\n        }\n\n        // PRIVATE\n        private bool findError(GameObject gameObject, MonoBehaviour[] components, bool printError = false)\n        {\n            if (showErrorIconWhenTagIsUndefined)\n            {\n                try\n                {\n                    gameObject.tag.CompareTo(null);\n                }\n                catch\n                {\n                    if (printError)\n                    {\n                        appendErrorLine(\"Tag is undefined\");\n                    }\n                    else\n                    {\n                        return true;\n                    }\n                }\n\n                if (LayerMask.LayerToName(gameObject.layer).Equals(\"\"))\n                {\n                    if (printError)\n                    {\n                        appendErrorLine(\"Layer is undefined\");\n                    }\n                    else\n                    {\n                        return true;\n                    }\n                }\n            }\n\n            for (int i = 0; i < components.Length; i++)\n            {\n                MonoBehaviour monoBehaviour = components[i];\n                if (monoBehaviour == null)\n                {\n                    if (showErrorIconScriptIsMissing)\n                    {\n                        if (printError)\n                        {\n                            appendErrorLine(\"Component #\" + i + \" is missing\");\n                        }\n                        else\n                        {\n                            return true;\n                        }\n                    }\n                }\n                else\n                {\n                    if (ignoreErrorOfMonoBehaviours != null)\n                    {\n                        for (int j = ignoreErrorOfMonoBehaviours.Count - 1; j >= 0; j--)\n                        {\n                            if (monoBehaviour.GetType().FullName.Contains(ignoreErrorOfMonoBehaviours[j]))\n                            {\n                                return false;\n                            }\n                        }\n                    }\n\n                    if (showErrorIconMissingEventMethod)\n                    {\n                        if (monoBehaviour.gameObject.activeSelf || showErrorForDisabledComponents)\n                        {\n                            try\n                            {\n                                if (isUnityEventsNullOrMissing(monoBehaviour, printError))\n                                {\n                                    if (!printError)\n                                    {\n                                        return true;\n                                    }\n                                }\n                            }\n                            catch\n                            {\n                            }\n                        }\n                    }\n\n                    if (showErrorTypeReferenceIsNull || showErrorTypeStringIsEmpty || showErrorTypeReferenceIsMissing)\n                    {\n                        if (!monoBehaviour.enabled && !showErrorForDisabledComponents) continue;\n                        if (!monoBehaviour.gameObject.activeSelf && !showErrorForDisabledGameObjects) continue;\n\n                        Type type = monoBehaviour.GetType();\n\n                        while (type != null)\n                        {\n                            BindingFlags bf = BindingFlags.Instance | BindingFlags.Public;\n                            if (!type.FullName.Contains(\"UnityEngine\"))\n                                bf |= BindingFlags.NonPublic;\n                            FieldInfo[] fieldArray = type.GetFields(bf);\n\n                            for (int j = 0; j < fieldArray.Length; j++)\n                            {\n                                FieldInfo field = fieldArray[j];\n\n                                if (System.Attribute.IsDefined(field, typeof(HideInInspector)) ||\n                                    System.Attribute.IsDefined(field, typeof(HierarchyNullableAttribute)) ||\n                                    System.Attribute.IsDefined(field, typeof(NonSerializedAttribute)) ||\n                                    field.IsStatic) continue;\n\n                                if (field.IsPrivate || !field.IsPublic)\n                                {\n                                    if (!Attribute.IsDefined(field, typeof(SerializeField)))\n                                    {\n                                        continue;\n                                    }\n                                }\n\n                                object value = field.GetValue(monoBehaviour);\n\n                                try\n                                {\n                                    if (showErrorTypeStringIsEmpty && field.FieldType == typeof(string) &&\n                                        value != null && ((string)value).Equals(\"\"))\n                                    {\n                                        if (printError)\n                                        {\n                                            appendErrorLine(monoBehaviour.GetType().Name + \".\" + field.Name +\n                                                            \": String value is empty\");\n                                            continue;\n                                        }\n                                        else\n                                        {\n                                            return true;\n                                        }\n                                    }\n                                }\n                                catch\n                                {\n                                }\n\n                                try\n                                {\n                                    if (showErrorTypeReferenceIsMissing && value != null && value is Component &&\n                                        (Component)value == null)\n                                    {\n                                        if (printError)\n                                        {\n                                            appendErrorLine(monoBehaviour.GetType().Name + \".\" + field.Name +\n                                                            \": Reference is missing\");\n                                            continue;\n                                        }\n                                        else\n                                        {\n                                            return true;\n                                        }\n                                    }\n                                }\n                                catch\n                                {\n                                }\n\n                                try\n                                {\n                                    if (showErrorTypeReferenceIsNull && (value == null || value.Equals(null)))\n                                    {\n                                        if (printError)\n                                        {\n                                            appendErrorLine(monoBehaviour.GetType().Name + \".\" + field.Name +\n                                                            \": Reference is null\");\n                                            continue;\n                                        }\n                                        else\n                                        {\n                                            return true;\n                                        }\n                                    }\n                                }\n                                catch\n                                {\n                                }\n\n                                try\n                                {\n                                    if (showErrorTypeReferenceIsNull && value != null && (value is IEnumerable))\n                                    {\n                                        foreach (var item in (IEnumerable)value)\n                                        {\n                                            if (item == null || item.Equals(null))\n                                            {\n                                                if (printError)\n                                                {\n                                                    appendErrorLine(monoBehaviour.GetType().Name + \".\" + field.Name +\n                                                                    \": IEnumerable has value with null reference\");\n                                                    continue;\n                                                }\n                                                else\n                                                {\n                                                    return true;\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                                catch\n                                {\n                                }\n                            }\n\n                            type = type.BaseType;\n                        }\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        private List<string> targetPropertiesNames = new List<string>(10);\n\n        private bool isUnityEventsNullOrMissing(MonoBehaviour monoBehaviour, bool printError)\n        {\n            targetPropertiesNames.Clear();\n            FieldInfo[] fieldArray = monoBehaviour.GetType()\n                .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);\n\n            for (int i = fieldArray.Length - 1; i >= 0; i--)\n            {\n                FieldInfo field = fieldArray[i];\n                if (field.FieldType == typeof(UnityEventBase) || field.FieldType.IsSubclassOf(typeof(UnityEventBase)))\n                {\n                    targetPropertiesNames.Add(field.Name);\n                }\n            }\n\n            if (targetPropertiesNames.Count > 0)\n            {\n                SerializedObject serializedMonoBehaviour = new SerializedObject(monoBehaviour);\n                for (int i = targetPropertiesNames.Count - 1; i >= 0; i--)\n                {\n                    string targetProperty = targetPropertiesNames[i];\n\n                    SerializedProperty property = serializedMonoBehaviour.FindProperty(targetProperty);\n                    SerializedProperty propertyRelativeArrray =\n                        property.FindPropertyRelative(\"m_PersistentCalls.m_Calls\");\n\n                    for (int j = propertyRelativeArrray.arraySize - 1; j >= 0; j--)\n                    {\n                        SerializedProperty arrayElementAtIndex = propertyRelativeArrray.GetArrayElementAtIndex(j);\n\n                        SerializedProperty propertyTarget = arrayElementAtIndex.FindPropertyRelative(\"m_Target\");\n                        if (propertyTarget.objectReferenceValue == null)\n                        {\n                            if (printError)\n                            {\n                                appendErrorLine(monoBehaviour.GetType().Name + \": Event object reference is null\");\n                            }\n                            else\n                            {\n                                return true;\n                            }\n                        }\n\n                        SerializedProperty propertyMethodName =\n                            arrayElementAtIndex.FindPropertyRelative(\"m_MethodName\");\n                        if (string.IsNullOrEmpty(propertyMethodName.stringValue))\n                        {\n                            if (printError)\n                            {\n                                appendErrorLine(monoBehaviour.GetType().Name +\n                                                \": Event handler function is not selected\");\n                                continue;\n                            }\n                            else\n                            {\n                                return true;\n                            }\n                        }\n\n                        string argumentAssemblyTypeName = arrayElementAtIndex.FindPropertyRelative(\"m_Arguments\")\n                            .FindPropertyRelative(\"m_ObjectArgumentAssemblyTypeName\").stringValue;\n                        System.Type argumentAssemblyType;\n                        if (!string.IsNullOrEmpty(argumentAssemblyTypeName))\n                            argumentAssemblyType = System.Type.GetType(argumentAssemblyTypeName, false) ??\n                                                   typeof(UnityEngine.Object);\n                        else argumentAssemblyType = typeof(UnityEngine.Object);\n\n                        UnityEventBase dummyEvent;\n                        System.Type propertyTypeName =\n                            System.Type.GetType(property.FindPropertyRelative(\"m_TypeName\").stringValue, false);\n                        if (propertyTypeName == null) dummyEvent = (UnityEventBase)new UnityEvent();\n                        else dummyEvent = Activator.CreateInstance(propertyTypeName) as UnityEventBase;\n\n                        if (!UnityEventDrawer.IsPersistantListenerValid(dummyEvent, propertyMethodName.stringValue,\n                                propertyTarget.objectReferenceValue,\n                                (PersistentListenerMode)arrayElementAtIndex.FindPropertyRelative(\"m_Mode\")\n                                    .enumValueIndex, argumentAssemblyType))\n                        {\n                            if (printError)\n                            {\n                                appendErrorLine(monoBehaviour.GetType().Name + \": Event handler function is missing\");\n                            }\n                            else\n                            {\n                                return true;\n                            }\n                        }\n                    }\n                }\n            }\n\n            return false;\n        }\n\n        private void appendErrorLine(string error)\n        {\n            errorCount++;\n            errorStringBuilder.Append(errorCount.ToString());\n            errorStringBuilder.Append(\") \");\n            errorStringBuilder.AppendLine(error);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/ErrorComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7026b875e5a28ee48b737e5d4b7ef24b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/GameObjectIconComponent.cs",
    "content": "using System;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\nusing System.Reflection;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class GameObjectIconComponent: BaseComponent\n    {\n        // PRIVATE\n        private MethodInfo getIconMethodInfo;\n        private object[] getIconMethodParams;\n\n        // CONSTRUCTOR\n        public GameObjectIconComponent ()\n        {\n            rect.width = 14;\n            rect.height = 14;\n\n            getIconMethodInfo   = typeof(EditorGUIUtility).GetMethod(\"GetIconForObject\", BindingFlags.NonPublic | BindingFlags.Static );\n            getIconMethodParams = new object[1];\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.GameObjectIconShow                 , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.GameObjectIconShowDuringPlayMode   , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.GameObjectIconSize                          , settingsChanged);\n            settingsChanged();\n        }\n        \n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled = HierarchySettings.getInstance().get<bool>(HierarchySetting.GameObjectIconShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.GameObjectIconShowDuringPlayMode);\n            HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get<int>(HierarchySetting.GameObjectIconSize);\n            rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13));     \n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < rect.width + 2)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= rect.width + 2;\n                rect.x = curRect.x;\n                rect.y = curRect.y - (rect.height - 16) / 2;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {                      \n            getIconMethodParams[0] = gameObject;\n            Texture2D icon = (Texture2D)getIconMethodInfo.Invoke(null, getIconMethodParams );    \n            if (icon != null) \n                GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit, true);\n        }\n                \n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition))\n            {\n                currentEvent.Use();\n\n                Type iconSelectorType = Assembly.Load(\"UnityEditor\").GetType(\"UnityEditor.IconSelector\");\n                MethodInfo showIconSelectorMethodInfo = iconSelectorType.GetMethod(\"ShowAtPosition\", BindingFlags.Static | BindingFlags.NonPublic);\n                showIconSelectorMethodInfo.Invoke(null, new object[] { gameObject, rect, true });\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/GameObjectIconComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1a5637cc504eddd4b960d67f4547b651\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/LayerIconComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class LayerIconComponent: BaseComponent\n    {\n        private List<LayerTexture> layerTextureList;\n\n        // CONSTRUCTOR\n        public LayerIconComponent()\n        {\n            rect.width  = 14;\n            rect.height = 14;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconSize              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LayerIconList              , settingsChanged);\n            settingsChanged();\n        }\n        \n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.LayerIconShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.LayerIconShowDuringPlayMode);\n            HierarchySizeAll size      = (HierarchySizeAll)HierarchySettings.getInstance().get<int>(HierarchySetting.LayerIconSize);\n            rect.width = rect.height    = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13));        \n            this.layerTextureList = LayerTexture.loadLayerTextureList();\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < rect.width)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= rect.width + 2;\n                rect.x = curRect.x;\n                rect.y = curRect.y - (rect.height - 16) / 2;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {                       \n            string gameObjectLayerName = LayerMask.LayerToName(gameObject.layer);\n\n            LayerTexture layerTexture = layerTextureList.Find(t => t.layer == gameObjectLayerName);\n            if (layerTexture != null && layerTexture.texture != null)\n            {\n                GUI.DrawTexture(rect, layerTexture.texture, ScaleMode.ScaleToFit, true);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/LayerIconComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6be765b80f12e6e4c80a42eb744b4df6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/LockComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class LockComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color activeColor;\n        private Color inactiveColor;\n        private Texture2D lockButtonTexture;\n        private bool showModifierWarning;\n        private int targetLockState = -1;\n\n        // CONSTRUCTOR\n        public LockComponent()\n        {\n            rect.width = 13;\n\n            lockButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyLockButton);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalShowModifierWarning , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShow                      , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShowDuringPlayMode        , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor         , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor       , settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            showModifierWarning         = HierarchySettings.getInstance().get<bool>(HierarchySetting.AdditionalShowModifierWarning);\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.LockShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.LockShowDuringPlayMode);\n            activeColor                 = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor);\n            inactiveColor               = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 13)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 13;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {  \n            bool isLock = isGameObjectLock(gameObject, objectList);\n\n            if (isLock == true && (gameObject.hideFlags & HideFlags.NotEditable) != HideFlags.NotEditable)\n            {\n                gameObject.hideFlags |= HideFlags.NotEditable;\n                EditorUtility.SetDirty(gameObject);\n            }\n            else if (isLock == false && (gameObject.hideFlags & HideFlags.NotEditable) == HideFlags.NotEditable)\n            {\n                gameObject.hideFlags ^= HideFlags.NotEditable;\n                EditorUtility.SetDirty(gameObject);\n            }\n\n            HierarchyColorUtils.setColor(isLock ? activeColor : inactiveColor);\n            GUI.DrawTexture(rect, lockButtonTexture);\n            HierarchyColorUtils.clearColor();\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition))\n            {\n                bool isLock = isGameObjectLock(gameObject, objectList);\n\n                if (currentEvent.type == EventType.MouseDown)\n                {\n                    targetLockState = ((!isLock) == true ? 1 : 0);\n                }\n                else if (currentEvent.type == EventType.MouseDrag && targetLockState != -1)\n                {\n                    if (targetLockState == (isLock == true ? 1 : 0)) return;\n                } \n                else\n                {\n                    targetLockState = -1;\n                    return;\n                }\n\n                List<GameObject> targetGameObjects = new List<GameObject>();\n                if (currentEvent.shift) \n                {\n                    if (!showModifierWarning || EditorUtility.DisplayDialog(\"Change locking\", \"Are you sure you want to \" + (isLock ? \"unlock\" : \"lock\") + \" this GameObject and all its children? (You can disable this warning in the settings)\", \"Yes\", \"Cancel\"))\n                    {\n                        getGameObjectListRecursive(gameObject, ref targetGameObjects);           \n                    }\n                }\n                else if (currentEvent.alt)\n                {\n                    if (gameObject.transform.parent != null)\n                    {\n                        if (!showModifierWarning || EditorUtility.DisplayDialog(\"Change locking\", \"Are you sure you want to \" + (isLock ? \"unlock\" : \"lock\") + \" this GameObject and its siblings? (You can disable this warning in the settings)\", \"Yes\", \"Cancel\"))\n                        {\n                            getGameObjectListRecursive(gameObject.transform.parent.gameObject, ref targetGameObjects, 1);\n                            targetGameObjects.Remove(gameObject.transform.parent.gameObject);\n                        }\n                    }\n                    else\n                    {\n                        Debug.Log(\"This action for root objects is supported only for Unity3d 5.3.3 and above\");\n                        return;\n                    }\n                }\n                else \n                {\n                    if (Selection.Contains(gameObject))\n                    {\n                        targetGameObjects.AddRange(Selection.gameObjects);\n                    }\n                    else\n                    {\n                        getGameObjectListRecursive(gameObject, ref targetGameObjects, 0);\n                    };\n                }\n                \n                setLock(targetGameObjects, objectList, !isLock);\n                currentEvent.Use();\n            }\n        } \n\n        public override void disabledHandler(GameObject gameObject, ObjectList objectList)\n        {\t\n            if (objectList != null && objectList.lockedObjects.Contains(gameObject))\n            {\n                objectList.lockedObjects.Remove(gameObject);\n                gameObject.hideFlags &= ~HideFlags.NotEditable;\n                EditorUtility.SetDirty(gameObject);\n            }\n        }\n\n        // PRIVATE\n        private bool isGameObjectLock(GameObject gameObject, ObjectList objectList)\n        {\n            return objectList == null ? false : objectList.lockedObjects.Contains(gameObject);\n        }\n        \n        private void setLock(List<GameObject> gameObjects, ObjectList objectList, bool targetLock)\n        {\n            if (gameObjects.Count == 0) return;\n\n            if (objectList == null) objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[0], true);\n            Undo.RecordObject(objectList, targetLock ? \"Lock\" : \"Unlock\");   \n            \n            for (int i = gameObjects.Count - 1; i >= 0; i--)\n            {     \n                GameObject curGameObject = gameObjects[i];\n                Undo.RecordObject(curGameObject, targetLock ? \"Lock\" : \"Unlock\");\n                \n                if (targetLock)\n                {\n                    curGameObject.hideFlags |= HideFlags.NotEditable;\n                    if (!objectList.lockedObjects.Contains(curGameObject))\n                        objectList.lockedObjects.Add(curGameObject);\n                }\n                else\n                {\n                    curGameObject.hideFlags &= ~HideFlags.NotEditable;\n                    objectList.lockedObjects.Remove(curGameObject);\n                }\n                \n                EditorUtility.SetDirty(curGameObject);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/LockComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f27ebb809ba98144394f4facad9a7494\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/MonoBehaviorIconComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class MonoBehaviorIconComponent: BaseComponent\n    {\n        // CONST\n        private const float TREE_STEP_WIDTH  = 14.0f;\n        private const float TREE_STEP_HEIGHT = 16.0f;\n\n        // PRIVATE\n        private Texture2D monoBehaviourIconTexture;   \n        private Texture2D monoBehaviourIconObjectTexture; \n        private bool ignoreUnityMonobehaviour;\n        private Color iconColor;\n        private bool showTreeMap;\n\n        // CONSTRUCTOR \n        public MonoBehaviorIconComponent()\n        {\n            rect.width  = 14;\n            rect.height = 16;\n            \n            monoBehaviourIconTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyMonoBehaviourIcon);\n            monoBehaviourIconObjectTexture  = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapObject);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconShow                     , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconShowDuringPlayMode       , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.MonoBehaviourIconColor                    , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapShow                               , settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            ignoreUnityMonobehaviour    = HierarchySettings.getInstance().get<bool>(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour);\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.MonoBehaviourIconShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.MonoBehaviourIconShowDuringPlayMode);\n            iconColor                   = HierarchySettings.getInstance().getColor(HierarchySetting.MonoBehaviourIconColor);\n            showTreeMap                 = HierarchySettings.getInstance().get<bool>(HierarchySetting.TreeMapShow);\n            EditorApplication.RepaintHierarchyWindow();  \n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            bool foundCustomComponent = false;   \n            if (ignoreUnityMonobehaviour)\n            {\n                Component[] components = gameObject.GetComponents<MonoBehaviour>();                \n                for (int i = components.Length - 1; i >= 0; i--)\n                {\n                    if (components[i] != null && !components[i].GetType().FullName.Contains(\"UnityEngine\")) \n                    {\n                        foundCustomComponent = true;\n                        break;\n                    }\n                }                \n            }\n            else\n            {\n                foundCustomComponent = gameObject.GetComponent<MonoBehaviour>() != null;\n            }\n\n            if (foundCustomComponent)\n            {\n                int ident = Mathf.FloorToInt(selectionRect.x / TREE_STEP_WIDTH) - 1;\n\n                rect.x = ident * TREE_STEP_WIDTH;\n                rect.y = selectionRect.y;\n                rect.width = 16;\n\n                #if UNITY_2018_3_OR_NEWER\n                    rect.x += TREE_STEP_WIDTH + 1;\n                    rect.width += 1;\n                #elif UNITY_5_6_OR_NEWER\n                    \n                #elif UNITY_5_3_OR_NEWER\n                    rect.x += TREE_STEP_WIDTH;\n                #endif                \n\n                HierarchyColorUtils.setColor(iconColor);\n                GUI.DrawTexture(rect, monoBehaviourIconTexture);\n                HierarchyColorUtils.clearColor();\n\n                if (!showTreeMap && gameObject.transform.childCount == 0)\n                {\n                    rect.width = 14;\n                    GUI.DrawTexture(rect, monoBehaviourIconObjectTexture);\n                }\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/MonoBehaviorIconComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a698db12abba706458883608fe26624b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/PrefabComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class PrefabComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color activeColor;\n        private Color inactiveColor;\n        private Texture2D prefabTexture;\n        private bool showPrefabConnectedIcon;\n\n        // CONSTRUCTOR\n        public PrefabComponent()\n        {\n            rect.width = 9;\n\n            prefabTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyPrefabIcon);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.PrefabShowBreakedPrefabsOnly  , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.PrefabShow                    , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor         , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor       , settingsChanged);\n            settingsChanged();\n        }\n        \n        // PRIVATE\n        private void settingsChanged()\n        {\n            showPrefabConnectedIcon = HierarchySettings.getInstance().get<bool>(HierarchySetting.PrefabShowBreakedPrefabsOnly);\n            enabled                 = HierarchySettings.getInstance().get<bool>(HierarchySetting.PrefabShow);\n            activeColor             = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor);\n            inactiveColor           = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 9)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 9;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                return LayoutStatus.Success;\n            }\n        }\n        \n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            #if UNITY_2018_3_OR_NEWER\n                PrefabInstanceStatus prefabStatus = PrefabUtility.GetPrefabInstanceStatus(gameObject);\n                if (prefabStatus == PrefabInstanceStatus.MissingAsset ||\n                    prefabStatus == PrefabInstanceStatus.Disconnected) {\n                    HierarchyColorUtils.setColor(inactiveColor);\n                    GUI.DrawTexture(rect, prefabTexture);\n                    HierarchyColorUtils.clearColor();\n                } else if (!showPrefabConnectedIcon && prefabStatus != PrefabInstanceStatus.NotAPrefab) {\n                    HierarchyColorUtils.setColor(activeColor);\n                    GUI.DrawTexture(rect, prefabTexture);\n                    HierarchyColorUtils.clearColor();\n                }\n            #else\n                PrefabType prefabType = PrefabUtility.GetPrefabType(gameObject);\n                if (prefabType == PrefabType.MissingPrefabInstance || \n                    prefabType == PrefabType.DisconnectedPrefabInstance ||\n                    prefabType == PrefabType.DisconnectedModelPrefabInstance)\n                {\n                    QColorUtils.setColor(inactiveColor);\n                    GUI.DrawTexture(rect, prefabTexture);\n                    QColorUtils.clearColor();\n                }\n                else if (!showPrefabConnectedIcon && prefabType != PrefabType.None)\n                {\n                    QColorUtils.setColor(activeColor);\n                    GUI.DrawTexture(rect, prefabTexture);\n                    QColorUtils.clearColor();\n                }\n            #endif\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/PrefabComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8122ed3c57f6b3847a0daefdae539039\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/RendererComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class RendererComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color activeColor;\n        private Color inactiveColor;\n        private Color specialColor;\n        private Texture2D rendererButtonTexture;\n        private int targetRendererMode = -1; \n\n        // CONSTRUCTOR\n        public RendererComponent()\n        {\n            rect.width = 12;\n\n            rendererButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyRendererButton);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.RendererShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.RendererShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor     , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor   , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalSpecialColor    , settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.RendererShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.RendererShowDuringPlayMode);\n            activeColor                 = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor);\n            inactiveColor               = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n            specialColor                = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalSpecialColor);\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 12)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 12;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void disabledHandler(GameObject gameObject, ObjectList objectList)\n        {\n            if (objectList != null && objectList.wireframeHiddenObjects.Contains(gameObject))\n            {      \n                objectList.wireframeHiddenObjects.Remove(gameObject);\n                Renderer renderer = gameObject.GetComponent<Renderer>();\n                if (renderer != null) setSelectedRenderState(renderer, false);\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            Renderer renderer = gameObject.GetComponent<Renderer>();\n            if (renderer != null)\n            {\n                bool wireframeHiddenObjectsContains = isWireframeHidden(gameObject, objectList);\n                if (wireframeHiddenObjectsContains)\n                {\n                    HierarchyColorUtils.setColor(specialColor);\n                    GUI.DrawTexture(rect, rendererButtonTexture);\n                    HierarchyColorUtils.clearColor();\n                }\n                else if (renderer.enabled)\n                {\n                    HierarchyColorUtils.setColor(activeColor);\n                    GUI.DrawTexture(rect, rendererButtonTexture);\n                    HierarchyColorUtils.clearColor();\n                }\n                else\n                {\n                    HierarchyColorUtils.setColor(inactiveColor);\n                    GUI.DrawTexture(rect, rendererButtonTexture);\n                    HierarchyColorUtils.clearColor();\n                }\n            }\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition))\n            {\n                Renderer renderer = gameObject.GetComponent<Renderer>();\n                if (renderer != null)\n                {\n                    bool wireframeHiddenObjectsContains = isWireframeHidden(gameObject, objectList);\n                    bool isEnabled = renderer.enabled;\n                    \n                    if (currentEvent.type == EventType.MouseDown)\n                    {\n                        targetRendererMode = ((!isEnabled) == true ? 1 : 0);\n                    }\n                    else if (currentEvent.type == EventType.MouseDrag && targetRendererMode != -1)\n                    {\n                        if (targetRendererMode == (isEnabled == true ? 1 : 0)) return;\n                    } \n                    else\n                    {\n                        targetRendererMode = -1;\n                        return;\n                    }\n\n                    Undo.RecordObject(renderer, \"renderer visibility change\");                    \n                    \n                    if (currentEvent.control || currentEvent.command)\n                    {\n                        if (!wireframeHiddenObjectsContains)\n                        {\n                            setSelectedRenderState(renderer, true);\n                            SceneView.RepaintAll();\n                            setWireframeMode(gameObject, objectList, true);\n                        }\n                    }\n                    else\n                    {\n                        if (wireframeHiddenObjectsContains)\n                        {\n                            setSelectedRenderState(renderer, false);\n                            SceneView.RepaintAll();\n                            setWireframeMode(gameObject, objectList, false);\n                        }\n                        else\n                        {\n                            Undo.RecordObject(renderer, isEnabled ? \"Disable Component\" : \"Enable Component\");\n                            renderer.enabled = !isEnabled;\n                        }\n                    }\n                    \n                    EditorUtility.SetDirty(gameObject);\n                }\n                currentEvent.Use();\n            }\n        }\n\n        // PRIVATE\n        public bool isWireframeHidden(GameObject gameObject, ObjectList objectList)\n        {\n            return objectList == null ? false : objectList.wireframeHiddenObjects.Contains(gameObject);\n        }\n        \n        public void setWireframeMode(GameObject gameObject, ObjectList objectList, bool targetWireframe)\n        {\n            if (objectList == null && targetWireframe) objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObject, true);\n            if (objectList != null)\n            {\n                Undo.RecordObject(objectList, \"Renderer Visibility Change\");\n                if (targetWireframe) objectList.wireframeHiddenObjects.Add(gameObject);\n                else objectList.wireframeHiddenObjects.Remove(gameObject);\n                EditorUtility.SetDirty(objectList);\n            }\n        }\n\n        static public void setSelectedRenderState(Renderer renderer, bool visible)\n        {\n            #if UNITY_5_5_OR_NEWER\n            EditorUtility.SetSelectedRenderState(renderer, visible ? EditorSelectedRenderState.Wireframe : EditorSelectedRenderState.Hidden);\n            #else\n            EditorUtility.SetSelectedWireframeHidden(renderer, visible);\n            #endif\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/RendererComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cff04b7651ffbf546aa976ab3f1203ec\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/SeparatorComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class SeparatorComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color separatorColor;\n        private Color evenShadingColor;\n        private Color oddShadingColor;\n        private bool showRowShading;\n\n        // CONSTRUCTOR\n        public SeparatorComponent ()\n        {\n            showComponentDuringPlayMode = true;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorShowRowShading   , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorShow             , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorColor                , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorEvenRowShadingColor  , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.SeparatorOddRowShadingColor , settingsChanged);\n\n            settingsChanged();\n        }\n        \n        // PRIVATE\n        private void settingsChanged()\n        {\n            showRowShading   = HierarchySettings.getInstance().get<bool>(HierarchySetting.SeparatorShowRowShading);\n            enabled          = HierarchySettings.getInstance().get<bool>(HierarchySetting.SeparatorShow);\n            evenShadingColor = HierarchySettings.getInstance().getColor(HierarchySetting.SeparatorEvenRowShadingColor);\n            oddShadingColor  = HierarchySettings.getInstance().getColor(HierarchySetting.SeparatorOddRowShadingColor);\n            separatorColor   = HierarchySettings.getInstance().getColor(HierarchySetting.SeparatorColor);\n        }\n\n        // DRAW\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            rect.y = selectionRect.y;\n            rect.width = selectionRect.width + selectionRect.x;\n            rect.height = 1;\n            rect.x = 0;\n\n            EditorGUI.DrawRect(rect, separatorColor);\n\n            if (showRowShading)\n            {\n                selectionRect.width += selectionRect.x;\n                selectionRect.x = 0;\n                selectionRect.height -=1;\n                selectionRect.y += 1;\n                EditorGUI.DrawRect(selectionRect, ((Mathf.FloorToInt(((selectionRect.y - 4) / 16) % 2) == 0)) ? evenShadingColor : oddShadingColor);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/SeparatorComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 86f5d0dd87df7d441a321be0035d2871\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/StaticComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class StaticComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color activeColor;\n        private Color inactiveColor;\n        private StaticEditorFlags staticFlags;\n        private GameObject[] gameObjects;\n        private Texture2D staticButton;\n        private Color32[] staticButtonColors;\n\n        // CONSTRUCTOR\n        public StaticComponent()\n        {\n            rect.width = 11;\n            rect.height = 10;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.StaticShow                , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.StaticShowDuringPlayMode  , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor     , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor   , settingsChanged);\n\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.StaticShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.StaticShowDuringPlayMode);\n            activeColor                 = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor);\n            inactiveColor               = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 13)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 13;\n                rect.x = curRect.x;\n                rect.y = curRect.y + 4;\n                staticFlags = GameObjectUtility.GetStaticEditorFlags(gameObject);\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            if (staticButton == null)\n            {\n                staticButton = new Texture2D(11, 10, TextureFormat.ARGB32, false, true);\n                staticButtonColors = new Color32[11 * 10];\n            }\n\n            #if UNITY_4_6 || UNITY_4_7\n            drawQuad(39, 5, 4, ((staticFlags & StaticEditorFlags.LightmapStatic       ) > 0));\n            drawQuad(33, 5, 4, ((staticFlags & StaticEditorFlags.BatchingStatic       ) > 0));\n            #else   \n            drawQuad(37, 3, 4, ((staticFlags & StaticEditorFlags.ContributeGI       ) > 0));\n            drawQuad(33, 3, 4, ((staticFlags & StaticEditorFlags.BatchingStatic       ) > 0));\n            drawQuad(41, 3, 4, ((staticFlags & StaticEditorFlags.ReflectionProbeStatic) > 0));\n            #endif\n            drawQuad( 0, 5, 2, ((staticFlags & StaticEditorFlags.OccludeeStatic       ) > 0));\n            drawQuad( 6, 5, 2, ((staticFlags & StaticEditorFlags.OccluderStatic       ) > 0));\n            drawQuad(88, 5, 2, ((staticFlags & StaticEditorFlags.NavigationStatic     ) > 0));\n            drawQuad(94, 5, 2, ((staticFlags & StaticEditorFlags.OffMeshLinkGeneration) > 0));\n\n            staticButton.SetPixels32(staticButtonColors);\n            staticButton.Apply();\n            GUI.DrawTexture(rect, staticButton);\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.type == EventType.MouseDown && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition))\n            {\n                currentEvent.Use();\n\n                int intStaticFlags = (int)staticFlags;\n                gameObjects = Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject };\n\n                GenericMenu menu = new GenericMenu();\n                menu.AddItem(new GUIContent(\"Nothing\"                   ), intStaticFlags == 0, staticChangeHandler, 0);\n                menu.AddItem(new GUIContent(\"Everything\"                ), intStaticFlags == -1, staticChangeHandler, -1);\n                menu.AddItem(new GUIContent(\"Lightmap Static\"           ), (intStaticFlags & (int)StaticEditorFlags.ContributeGI) > 0, staticChangeHandler, (int)StaticEditorFlags.ContributeGI);\n                menu.AddItem(new GUIContent(\"Occluder Static\"           ), (intStaticFlags & (int)StaticEditorFlags.OccluderStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.OccluderStatic);\n                menu.AddItem(new GUIContent(\"Batching Static\"           ), (intStaticFlags & (int)StaticEditorFlags.BatchingStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.BatchingStatic);\n                menu.AddItem(new GUIContent(\"Navigation Static\"         ), (intStaticFlags & (int)StaticEditorFlags.NavigationStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.NavigationStatic);\n                menu.AddItem(new GUIContent(\"Occludee Static\"           ), (intStaticFlags & (int)StaticEditorFlags.OccludeeStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.OccludeeStatic);\n                menu.AddItem(new GUIContent(\"Off Mesh Link Generation\"  ), (intStaticFlags & (int)StaticEditorFlags.OffMeshLinkGeneration) > 0, staticChangeHandler, (int)StaticEditorFlags.OffMeshLinkGeneration);\n                #if UNITY_4_6 || UNITY_4_7\n                #else\n                menu.AddItem(new GUIContent(\"Reflection Probe Static\"   ), (intStaticFlags & (int)StaticEditorFlags.ReflectionProbeStatic) > 0, staticChangeHandler, (int)StaticEditorFlags.ReflectionProbeStatic);\n                #endif\n                menu.ShowAsContext();\n            }\n        }\n\n        // PRIVATE\n        private void staticChangeHandler(object result)\n        {\n            int intResult = (int)result;\n            StaticEditorFlags resultStaticFlags = (StaticEditorFlags)result;\n            if (intResult != 0 && intResult != -1)\n            {\n                resultStaticFlags = staticFlags ^ resultStaticFlags;\n            }\n\n            for (int i = gameObjects.Length - 1; i >= 0; i--)\n            {\n                GameObject gameObject = gameObjects[i];\n                Undo.RecordObject(gameObject, \"Change Static Flags\");            \n                GameObjectUtility.SetStaticEditorFlags(gameObject, resultStaticFlags);\n                EditorUtility.SetDirty(gameObject);\n            }\n        }\n\n        private void drawQuad(int startPosition, int width, int height, bool isActiveColor)\n        {\n            Color32 color = isActiveColor ? activeColor : inactiveColor;\n            for (int iy = 0; iy < height; iy++)\n            {\n                for (int ix = 0; ix < width; ix++)\n                {\n                    int pos = startPosition + ix + iy * 11;\n                    staticButtonColors[pos].r = color.r;\n                    staticButtonColors[pos].g = color.g;\n                    staticButtonColors[pos].b = color.b;\n                    staticButtonColors[pos].a = color.a;\n                }\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/StaticComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bad9267f99b998b42adf5da1f9f75760\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/TagIconComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class TagIconComponent: BaseComponent\n    {\n        private List<TagTexture> tagTextureList;\n\n        // CONSTRUCTOR\n        public TagIconComponent()\n        {\n            rect.width  = 14;\n            rect.height = 14;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconShowDuringPlayMode, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconSize              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagIconList              , settingsChanged);\n            settingsChanged();\n        }\n        \n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled = HierarchySettings.getInstance().get<bool>(HierarchySetting.TagIconShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.TagIconShowDuringPlayMode);\n            HierarchySizeAll size = (HierarchySizeAll)HierarchySettings.getInstance().get<int>(HierarchySetting.TagIconSize);\n            rect.width = rect.height = (size == HierarchySizeAll.Normal ? 15 : (size == HierarchySizeAll.Big ? 16 : 13));        \n            this.tagTextureList = TagTexture.loadTagTextureList();\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < rect.width)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= rect.width + 2;\n                rect.x = curRect.x;\n                rect.y = curRect.y - (rect.height - 16) / 2;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {                       \n            string gameObjectTag = \"\";\n            try { gameObjectTag = gameObject.tag; }\n            catch {}\n\n            TagTexture tagTexture = tagTextureList.Find(t => t.tag == gameObjectTag);\n            if (tagTexture != null && tagTexture.texture != null)\n            {\n                GUI.DrawTexture(rect, tagTexture.texture, ScaleMode.ScaleToFit, true);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/TagIconComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 53c992a7ba1ab9747a352e958d4850b6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/TagLayerComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing System.Reflection;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class TagLayerComponent: BaseComponent\n    {\n        // PRIVATE\n        private GUIStyle labelStyle;\n        private HierarchyTagAndLayerShowType showType;\n        private Color layerColor;\n        private Color tagColor;       \n        private bool showAlways;\n        private bool sizeIsPixel;\n        private int pixelSize;\n        private float percentSize;\n        private GameObject[] gameObjects;\n        private float labelAlpha;\n        private HierarchyTagAndLayerLabelSize labelSize;\n        private Rect tagRect = new Rect();\n        private Rect layerRect = new Rect();\n        private bool needDrawTag;\n        private bool needDrawLayer;\n        private int layer;\n        private string tag;\n\n        // CONSTRUCTOR\n        public TagLayerComponent()\n        {\n            labelStyle = new GUIStyle();\n            labelStyle.fontSize = 8;\n            labelStyle.clipping = TextClipping.Clip;  \n            labelStyle.alignment = TextAnchor.MiddleLeft;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeShowType       , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerType               , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeValueType      , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeValuePixel     , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerSizeValuePercent   , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerLabelSize          , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerShow               , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerShowDuringPlayMode , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerTagLabelColor      , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerLayerLabelColor    , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerAligment           , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TagAndLayerLabelAlpha         , settingsChanged);\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            showAlways  = HierarchySettings.getInstance().get<int>(HierarchySetting.TagAndLayerType) == (int)HierarchyTagAndLayerType.Always;\n            showType    = (HierarchyTagAndLayerShowType)HierarchySettings.getInstance().get<int>(HierarchySetting.TagAndLayerSizeShowType);\n            sizeIsPixel = HierarchySettings.getInstance().get<int>(HierarchySetting.TagAndLayerSizeValueType) == (int)HierarchyTagAndLayerSizeType.Pixel;\n            pixelSize   = HierarchySettings.getInstance().get<int>(HierarchySetting.TagAndLayerSizeValuePixel);\n            percentSize = HierarchySettings.getInstance().get<float>(HierarchySetting.TagAndLayerSizeValuePercent);\n            labelSize   = (HierarchyTagAndLayerLabelSize)HierarchySettings.getInstance().get<int>(HierarchySetting.TagAndLayerLabelSize);\n            enabled     = HierarchySettings.getInstance().get<bool>(HierarchySetting.TagAndLayerShow);\n            tagColor    = HierarchySettings.getInstance().getColor(HierarchySetting.TagAndLayerTagLabelColor);\n            layerColor  = HierarchySettings.getInstance().getColor(HierarchySetting.TagAndLayerLayerLabelColor);\n            labelAlpha  = HierarchySettings.getInstance().get<float>(HierarchySetting.TagAndLayerLabelAlpha);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.TagAndLayerShowDuringPlayMode);\n\n            HierarchyTagAndLayerAligment aligment = (HierarchyTagAndLayerAligment)HierarchySettings.getInstance().get<int>(HierarchySetting.TagAndLayerAligment);\n            switch (aligment)\n            {\n                case HierarchyTagAndLayerAligment.Left  : labelStyle.alignment = TextAnchor.MiddleLeft;   break;\n                case HierarchyTagAndLayerAligment.Center: labelStyle.alignment = TextAnchor.MiddleCenter; break;\n                case HierarchyTagAndLayerAligment.Right : labelStyle.alignment = TextAnchor.MiddleRight;  break;\n            }\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            float textWidth = sizeIsPixel ? pixelSize : percentSize * rect.x;\n            rect.width = textWidth + 4;\n\n            if (maxWidth < rect.width)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= rect.width + 2;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                rect.y += (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n                //rect.height = EditorGUIUtility.singleLineHeight;\n\n                layer  = gameObject.layer; \n                tag = getTagName(gameObject);             \n                \n                needDrawTag   = (showType != HierarchyTagAndLayerShowType.Layer) && ((showAlways || tag   != \"Untagged\"));\n                needDrawLayer = (showType != HierarchyTagAndLayerShowType.Tag  ) && ((showAlways || layer != 0         ));\n\n                #if UNITY_2019_1_OR_NEWER\n                    if (labelSize == HierarchyTagAndLayerLabelSize.Big || (labelSize == HierarchyTagAndLayerLabelSize.BigIfSpecifiedOnlyTagOrLayer && needDrawTag != needDrawLayer)) \n                        labelStyle.fontSize = 8;\n                    else \n                        labelStyle.fontSize = 7;\n                #else\n                    if (labelSize == QHierarchyTagAndLayerLabelSize.Big || (labelSize == QHierarchyTagAndLayerLabelSize.BigIfSpecifiedOnlyTagOrLayer && needDrawTag != needDrawLayer)) \n                        labelStyle.fontSize = 9;\n                    else \n                        labelStyle.fontSize = 8;\n                #endif\n\n                if (needDrawTag) tagRect.Set(rect.x, rect.y - (needDrawLayer ? 4 : 0), rect.width, rect.height);                                                   \n                if (needDrawLayer) layerRect.Set(rect.x, rect.y + (needDrawTag ? 4 : 0), rect.width, rect.height);                    \n\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            if (needDrawTag ) \n            {\n                tagColor.a = (tag == \"Untagged\" ? labelAlpha : 1.0f);\n                labelStyle.normal.textColor = tagColor;\n                EditorGUI.LabelField(tagRect, tag, labelStyle);\n            }\n\n            if (needDrawLayer) \n            {\n                layerColor.a = (layer == 0 ? labelAlpha : 1.0f);\n                labelStyle.normal.textColor = layerColor;\n                EditorGUI.LabelField(layerRect, getLayerName(layer), labelStyle);\n            }\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {                       \n            if (Event.current.isMouse && currentEvent.type == EventType.MouseDown && Event.current.button == 0)\n            {\n                if (needDrawTag && needDrawLayer)\n                {\n                    tagRect.height = 8;\n                    layerRect.height = 8;\n                    tagRect.y += 4;\n                    layerRect.y += 4;\n                }\n\n                if (needDrawTag && tagRect.Contains(Event.current.mousePosition))\n                {\n                    gameObjects = Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject };\n                    showTagsContextMenu(tag);\n                    Event.current.Use();\n                }\n                else if (needDrawLayer && layerRect.Contains(Event.current.mousePosition))\n                {\n                    gameObjects = Selection.Contains(gameObject) ? Selection.gameObjects : new GameObject[] { gameObject };\n                    showLayersContextMenu(LayerMask.LayerToName(layer));\n                    Event.current.Use();\n                }\n            }\n        }\n\n        private string getTagName(GameObject gameObject)\n        {\n            string tag = \"Undefined\";\n            try { tag = gameObject.tag; }\n            catch {}\n            return tag;\n        }\n\n        public string getLayerName(int layer)\n        {\n            string layerName = LayerMask.LayerToName(layer);\n            if (layerName.Equals(\"\")) layerName = \"Undefined\";\n            return layerName;\n        }\n\n        // PRIVATE\n        private void showTagsContextMenu(string tag)\n        {\n            List<string> tags = new List<string>(UnityEditorInternal.InternalEditorUtility.tags);\n            \n            GenericMenu menu = new GenericMenu();\n            menu.AddItem(new GUIContent(\"Untagged\"  ), false, tagChangedHandler, \"Untagged\");\n            \n            for (int i = 0, n = tags.Count; i < n; i++)\n            {\n                string curTag = tags[i];\n                menu.AddItem(new GUIContent(curTag), tag == curTag, tagChangedHandler, curTag);\n            }\n            \n            menu.AddSeparator(\"\");\n            menu.AddItem(new GUIContent(\"Add Tag...\"  ), false, addTagOrLayerHandler, \"Tags\");\n            menu.ShowAsContext();\n        }\n\n        private void showLayersContextMenu(string layer)\n        {\n            List<string> layers = new List<string>(UnityEditorInternal.InternalEditorUtility.layers);\n            \n            GenericMenu menu = new GenericMenu();\n            menu.AddItem(new GUIContent(\"Default\"  ), false, layerChangedHandler, \"Default\");\n            \n            for (int i = 0, n = layers.Count; i < n; i++)\n            {\n                string curLayer = layers[i];\n                menu.AddItem(new GUIContent(curLayer), layer == curLayer, layerChangedHandler, curLayer);\n            }\n            \n            menu.AddSeparator(\"\");\n            menu.AddItem(new GUIContent(\"Add Layer...\"  ), false, addTagOrLayerHandler, \"Layers\");\n            menu.ShowAsContext();\n        }\n\n        private void tagChangedHandler(object newTag)\n        {\n            for (int i = gameObjects.Length - 1; i >= 0; i--)\n            {\n                GameObject gameObject = gameObjects[i];\n                Undo.RecordObject(gameObject, \"Change Tag\");\n                gameObject.tag = (string)newTag;\n                EditorUtility.SetDirty(gameObject);\n            }\n        }\n\n        private void layerChangedHandler(object newLayer)\n        {\n            int newLayerId = LayerMask.NameToLayer((string)newLayer);\n            for (int i = gameObjects.Length - 1; i >= 0; i--)\n            {\n                GameObject gameObject = gameObjects[i];\n                Undo.RecordObject(gameObject, \"Change Layer\");\n                gameObject.layer = newLayerId;\n                EditorUtility.SetDirty(gameObject);\n            }\n        }\n\n        private void addTagOrLayerHandler(object value)\n        {\n            PropertyInfo propertyInfo = typeof(EditorApplication).GetProperty(\"tagManager\", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetProperty);\n            UnityEngine.Object obj = (UnityEngine.Object)(propertyInfo.GetValue(null, null));\n            obj.GetType().GetField(\"m_DefaultExpandedFoldout\").SetValue(obj, value);\n            Selection.activeObject = obj;\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/TagLayerComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cde42cc8a02faf544ad81c7744878785\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/TreeMapComponent.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing System.Collections.Generic;\nusing System.Collections;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class TreeMapComponent: BaseComponent\n    {\n        // CONST\n        private const float TREE_STEP_WIDTH  = 14.0f;\n        \n        // PRIVATE\n        private Texture2D treeMapLevelTexture;       \n        private Texture2D treeMapLevel4Texture;       \n        private Texture2D treeMapCurrentTexture;   \n        private Texture2D treeMapLastTexture;\n        private Texture2D treeMapObjectTexture;    \n        private bool enhanced;\n        private bool transparentBackground;\n        private Color backgroundColor;\n        private Color treeMapColor;\n        \n        // CONSTRUCTOR\n        public TreeMapComponent()\n        { \n\n            treeMapLevelTexture   = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLevel);\n            treeMapLevel4Texture  = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLevel4);\n            treeMapCurrentTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapCurrent);\n            #if UNITY_2018_3_OR_NEWER\n                treeMapObjectTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLine);\n            #else\n                treeMapObjectTexture  = QResources.getInstance().getTexture(QTexture.QTreeMapObject);\n            #endif\n            treeMapLastTexture    = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTreeMapLast);\n            \n            rect.width  = 14;\n            rect.height = 16;\n            \n            showComponentDuringPlayMode = true;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalBackgroundColor, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapShow           , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapColor          , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapEnhanced       , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.TreeMapTransparentBackground, settingsChanged);\n            settingsChanged();\n        }\n        \n        // PRIVATE\n        private void settingsChanged() {\n            backgroundColor     = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalBackgroundColor);\n            enabled             = HierarchySettings.getInstance().get<bool>(HierarchySetting.TreeMapShow);\n            treeMapColor        = HierarchySettings.getInstance().getColor(HierarchySetting.TreeMapColor);\n            enhanced            = HierarchySettings.getInstance().get<bool>(HierarchySetting.TreeMapEnhanced);\n            transparentBackground = HierarchySettings.getInstance().get<bool>(HierarchySetting.TreeMapTransparentBackground);\n        }\n        \n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            rect.y = selectionRect.y;\n            \n            if (!transparentBackground) \n            {\n                rect.x = 0;\n                \n                rect.width = selectionRect.x - 14;\n                EditorGUI.DrawRect(rect, backgroundColor);\n                rect.width = 14;\n            }\n\n            return LayoutStatus.Success;\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            int childCount = gameObject.transform.childCount;\n            int level = Mathf.RoundToInt(selectionRect.x / 14.0f);\n\n            if (enhanced)\n            {\n                Transform gameObjectTransform = gameObject.transform;\n                Transform parentTransform = null;\n\n                for (int i = 0, j = level - 1; j >= 0; i++, j--)\n                {\n                    rect.x = 14 * j;\n                    if (i == 0)\n                    {\n                        if (childCount == 0) {\n                            #if UNITY_2018_3_OR_NEWER\n                                HierarchyColorUtils.setColor(treeMapColor);\n                            #endif\n                            GUI.DrawTexture(rect, treeMapObjectTexture);\n                        }\n                        gameObjectTransform = gameObject.transform;\n                    }\n                    else if (i == 1)\n                    {\n                        HierarchyColorUtils.setColor(treeMapColor);\n                        if (parentTransform == null) {\n                            if (gameObjectTransform.GetSiblingIndex() == gameObject.scene.rootCount - 1) {\n                                GUI.DrawTexture(rect, treeMapLastTexture);\n                            } else {\n                                GUI.DrawTexture(rect, treeMapCurrentTexture);\n                            }\n                        } else if (gameObjectTransform.GetSiblingIndex() == parentTransform.childCount - 1) {\n                            GUI.DrawTexture(rect, treeMapLastTexture);\n                        } else {\n                            GUI.DrawTexture(rect, treeMapCurrentTexture);\n                        }\n                        gameObjectTransform = parentTransform;\n                    }\n                    else\n                    {\n                        if (parentTransform == null) {\n                            if (gameObjectTransform.GetSiblingIndex() != gameObject.scene.rootCount - 1)\n                                GUI.DrawTexture(rect, treeMapLevelTexture);\n                        } else if (gameObjectTransform.GetSiblingIndex() != parentTransform.childCount - 1)\n                            GUI.DrawTexture(rect, treeMapLevelTexture);\n\n                        gameObjectTransform = parentTransform;                       \n                    }\n                    if (gameObjectTransform != null) \n\t\t\t\t\t\tparentTransform = gameObjectTransform.parent;\n\t\t\t\t\telse\n                        break;\n                }\n                HierarchyColorUtils.clearColor();\n            }\n            else\n            {\n                for (int i = 0, j = level - 1; j >= 0; i++, j--)\n                {\n                    rect.x = 14 * j;\n                    if (i == 0)\n                    {\n                        if (childCount > 0)\n                            continue;\n                        else {\n                            #if UNITY_2018_3_OR_NEWER\n                                HierarchyColorUtils.setColor(treeMapColor);\n                            #endif\n                            GUI.DrawTexture(rect, treeMapObjectTexture);\n                        }\n                    }\n                    else if (i == 1)\n                    {\n                        HierarchyColorUtils.setColor(treeMapColor);\n                        GUI.DrawTexture(rect, treeMapCurrentTexture);\n                    }\n                    else\n                    {\n                        rect.width = 14 * 4;\n                        rect.x -= 14 * 3;\n                        j -= 3;\n                        GUI.DrawTexture(rect, treeMapLevel4Texture);\n                        rect.width = 14;\n                    }\n                }\n                HierarchyColorUtils.clearColor();\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/TreeMapComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3956b2178bf9e494d9b0f059378da9bd\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/VerticesAndTrianglesCountComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class VerticesAndTrianglesCountComponent: BaseComponent\n    {\n        // PRIVATE\n        private GUIStyle labelStyle;\n        private Color verticesLabelColor;\n        private Color trianglesLabelColor;\n        private bool calculateTotalCount;\n        private bool showTrianglesCount;\n        private bool showVerticesCount;\n        private HierarchySize labelSize;\n\n        // CONSTRUCTOR\n        public VerticesAndTrianglesCountComponent ()\n        {\n            labelStyle = new GUIStyle();            \n            labelStyle.clipping = TextClipping.Clip;  \n            labelStyle.alignment = TextAnchor.MiddleRight;\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShow                  , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode    , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesCalculateTotalCount   , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShowTriangles         , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesShowVertices          , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesLabelSize             , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesVerticesLabelColor    , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor   , settingsChanged);\n\n            settingsChanged();\n        }\n\n        // PRIVATE\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.VerticesAndTrianglesShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode);\n            calculateTotalCount         = HierarchySettings.getInstance().get<bool>(HierarchySetting.VerticesAndTrianglesCalculateTotalCount);\n            showTrianglesCount          = HierarchySettings.getInstance().get<bool>(HierarchySetting.VerticesAndTrianglesShowTriangles);\n            showVerticesCount           = HierarchySettings.getInstance().get<bool>(HierarchySetting.VerticesAndTrianglesShowVertices);\n            verticesLabelColor          = HierarchySettings.getInstance().getColor(HierarchySetting.VerticesAndTrianglesVerticesLabelColor);\n            trianglesLabelColor         = HierarchySettings.getInstance().getColor(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor);\n            labelSize                   = (HierarchySize)HierarchySettings.getInstance().get<int>(HierarchySetting.VerticesAndTrianglesLabelSize);\n\n            #if UNITY_2019_1_OR_NEWER\n                labelStyle.fontSize = labelSize == HierarchySize.Big ? 7 : 6;\n                rect.width = labelSize == HierarchySize.Big ? 24 : 22;\n            #else\n                labelStyle.fontSize = labelSize == QHierarchySize.Big ? 9 : 8;\n                rect.width = labelSize == QHierarchySize.Big ? 33 : 25;\n            #endif\n        }   \n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < rect.width)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= rect.width + 2;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                #if UNITY_2019_1_OR_NEWER                \n                    rect.y += labelSize == HierarchySize.Big ? 2 : 1;\n                #endif\n                return LayoutStatus.Success;\n            }\n        }\n        \n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {  \n            int vertexCount = 0;\n            int triangleCount = 0;\n\n            MeshFilter[] meshFilterArray = calculateTotalCount ? gameObject.GetComponentsInChildren<MeshFilter>(true) : gameObject.GetComponents<MeshFilter>();\n            for (int i = 0; i < meshFilterArray.Length; i++)\n            {\n                Mesh sharedMesh = meshFilterArray[i].sharedMesh;\n                if (sharedMesh != null)\n                {\n                    if (showVerticesCount) vertexCount += sharedMesh.vertexCount;\n                    if (showTrianglesCount) triangleCount += sharedMesh.triangles.Length;\n                }\n            }\n\n            SkinnedMeshRenderer[] skinnedMeshRendererArray = calculateTotalCount ? gameObject.GetComponentsInChildren<SkinnedMeshRenderer>(true) : gameObject.GetComponents<SkinnedMeshRenderer>();\n            for (int i = 0; i < skinnedMeshRendererArray.Length; i++)\n            {\n                Mesh sharedMesh = skinnedMeshRendererArray[i].sharedMesh;\n                if (sharedMesh != null)\n                {   \n                    if (showVerticesCount) vertexCount += sharedMesh.vertexCount;\n                    if (showTrianglesCount) triangleCount += sharedMesh.triangles.Length;\n                }\n            }\n\n            triangleCount /= 3;\n\n            if (vertexCount > 0 || triangleCount > 0)\n            {\n                if (showTrianglesCount && showVerticesCount) \n                {\n                    rect.y -= 4;\n                    labelStyle.normal.textColor = verticesLabelColor;\n                    EditorGUI.LabelField(rect, getCountString(vertexCount), labelStyle);\n\n                    rect.y += 8;\n                    labelStyle.normal.textColor = trianglesLabelColor;\n                    EditorGUI.LabelField(rect, getCountString(triangleCount), labelStyle);\n                }\n                else if (showVerticesCount)\n                {\n                    labelStyle.normal.textColor = verticesLabelColor;\n                    EditorGUI.LabelField(rect, getCountString(vertexCount), labelStyle);\n                }\n                else\n                {\n                    labelStyle.normal.textColor = trianglesLabelColor;\n                    EditorGUI.LabelField(rect, getCountString(triangleCount), labelStyle);\n                }\n            }\n        }\n\n        // PRIVATE\n        private string getCountString(int count)\n        {\n            if (count < 1000) return count.ToString();\n            else if (count < 1000000) \n            {\n                if (count > 100000) return (count / 1000.0f).ToString(\"0\") + \"k\";\n                else return (count / 1000.0f).ToString(\"0.0\") + \"k\";\n            }\n            else \n            {\n                if (count > 10000000) return (count / 1000.0f).ToString(\"0\") + \"M\";\n                else return (count / 1000000.0f).ToString(\"0.0\") + \"M\";\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/VerticesAndTrianglesCountComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 087cec645530b2541832d66aeab19caa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/VisibilityComponent.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.HComponent\n{\n    public class VisibilityComponent: BaseComponent\n    {\n        // PRIVATE\n        private Color activeColor;\n        private Color inactiveColor;\n        private Color specialColor;\n        private Texture2D visibilityButtonTexture;\n        private Texture2D visibilityOffButtonTexture;\n        private int targetVisibilityState = -1;\n\n        // CONSTRUCTOR\n        public VisibilityComponent()\n        {\n            rect.width = 18;\n\n            visibilityButtonTexture    = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyVisibilityButton);\n            visibilityOffButtonTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyVisibilityOffButton);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VisibilityShow                , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.VisibilityShowDuringPlayMode  , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalActiveColor         , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor       , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalSpecialColor        , settingsChanged);\n            settingsChanged();\n        }\n\n        private void settingsChanged()\n        {\n            enabled                     = HierarchySettings.getInstance().get<bool>(HierarchySetting.VisibilityShow);\n            showComponentDuringPlayMode = HierarchySettings.getInstance().get<bool>(HierarchySetting.VisibilityShowDuringPlayMode);\n            activeColor                 = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalActiveColor);\n            inactiveColor               = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n            specialColor                = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalSpecialColor);\n        }\n\n        // DRAW\n        public override LayoutStatus layout(GameObject gameObject, ObjectList objectList, Rect selectionRect, ref Rect curRect, float maxWidth)\n        {\n            if (maxWidth < 18)\n            {\n                return LayoutStatus.Failed;\n            }\n            else\n            {\n                curRect.x -= 18;\n                rect.x = curRect.x;\n                rect.y = curRect.y;\n                return LayoutStatus.Success;\n            }\n        }\n\n        public override void disabledHandler(GameObject gameObject, ObjectList objectList)\n        {\n            if (objectList != null)\n            {\n                if (gameObject.activeSelf && objectList.editModeVisibileObjects.Contains(gameObject))\n                {\n                    objectList.editModeVisibileObjects.Remove(gameObject);\n                    gameObject.SetActive(false);\n                    EditorUtility.SetDirty(gameObject);\n                }\n                else if (!gameObject.activeSelf && objectList.editModeInvisibleObjects.Contains(gameObject))\n                {\n                    objectList.editModeInvisibleObjects.Remove(gameObject);\n                    gameObject.SetActive(true);\n                    EditorUtility.SetDirty(gameObject);\n                }\n            }\n        }\n\n        public override void draw(GameObject gameObject, ObjectList objectList, Rect selectionRect)\n        {\n            int visibility = gameObject.activeSelf ? 1 : 0;\n            \n            bool editModeVisibleObjectsContains = isEditModeVisibile(gameObject, objectList);\n            bool editModeInvisibleObjectsContains = isEditModeInvisibile(gameObject, objectList);\n            \n            if (!EditorApplication.isPlayingOrWillChangePlaymode && ((!gameObject.activeSelf && editModeVisibleObjectsContains) || (gameObject.activeSelf && editModeInvisibleObjectsContains)))\n                gameObject.SetActive(!gameObject.activeSelf);\n                        \n\n            Transform transform = gameObject.transform;\n            while (transform.parent != null)\n            {\n                transform = transform.parent;\n                if (!transform.gameObject.activeSelf) \n                {\n                    visibility = 2;\n                    break;\n                }\n            }\n                       \n            if (!EditorApplication.isPlayingOrWillChangePlaymode && (editModeVisibleObjectsContains || editModeInvisibleObjectsContains))\n            {\n                if (visibility == 0)\n                {\n                    HierarchyColorUtils.setColor(specialColor);\n                    GUI.DrawTexture(rect, visibilityOffButtonTexture);\n                }\n                else if (visibility == 1)\n                {\n                    HierarchyColorUtils.setColor(specialColor);\n                    GUI.DrawTexture(rect, visibilityButtonTexture);\n                }\n                else\n                {\n                    HierarchyColorUtils.setColor(specialColor, 1.0f, 0.4f);\n                    GUI.DrawTexture(rect, editModeVisibleObjectsContains ? visibilityButtonTexture : visibilityOffButtonTexture);\n                }\n            }\n            else\n            {\n                if (visibility == 0)\n                {\n                    HierarchyColorUtils.setColor(inactiveColor);\n                    GUI.DrawTexture(rect, visibilityOffButtonTexture);\n                }\n                else if (visibility == 1)\n                {\n                    HierarchyColorUtils.setColor(activeColor);\n                    GUI.DrawTexture(rect, visibilityButtonTexture);\n                }\n                else\n                {\n                    if (gameObject.activeSelf)\n                    {\n                        HierarchyColorUtils.setColor(activeColor, 0.65f, 0.65f);\n                        GUI.DrawTexture(rect, visibilityButtonTexture);                    \n                    }\n                    else\n                    {\n                        HierarchyColorUtils.setColor(inactiveColor, 0.85f, 0.85f);\n                        GUI.DrawTexture(rect, visibilityOffButtonTexture);                    \n                    }\n                }\n            }\n            HierarchyColorUtils.clearColor();\n        }\n\n        public override void eventHandler(GameObject gameObject, ObjectList objectList, Event currentEvent)\n        {\n            if (currentEvent.isMouse && currentEvent.button == 0 && rect.Contains(currentEvent.mousePosition))\n            {\n                if (currentEvent.type == EventType.MouseDown)\n                {\n                    targetVisibilityState = ((!gameObject.activeSelf) == true ? 1 : 0);\n                }\n                else if (currentEvent.type == EventType.MouseDrag && targetVisibilityState != -1)\n                {\n                    if (targetVisibilityState == (gameObject.activeSelf == true ? 1 : 0)) return;\n                } \n                else\n                {\n                    targetVisibilityState = -1;\n                    return;\n                }\n                                                            \n                bool showWarning = HierarchySettings.getInstance().get<bool>(HierarchySetting.AdditionalShowModifierWarning);\n                \n                List<GameObject> targetGameObjects = new List<GameObject>();\n                if (currentEvent.control || currentEvent.command) \n                {\n                    if (currentEvent.shift)\n                    {\n                        if (!showWarning || EditorUtility.DisplayDialog(\"Change edit-time visibility\", \"Are you sure you want to turn \" + (gameObject.activeSelf ? \"off\" : \"on\") + \" the edit-time visibility of this GameObject and all its children? (You can disable this warning in the settings)\", \"Yes\", \"Cancel\"))\n                        {\n                            getGameObjectListRecursive(gameObject, ref targetGameObjects);\n                        }\n                    }\n                    else if (currentEvent.alt)\n                    {\n                        if (gameObject.transform.parent != null)\n                        {\n                            if (!showWarning || EditorUtility.DisplayDialog(\"Change edit-time visibility\", \"Are you sure you want to turn \" + (gameObject.activeSelf ? \"off\" : \"on\") + \" the edit-time visibility this GameObject and its siblings? (You can disable this warning in the settings)\", \"Yes\", \"Cancel\"))\n                            {\n                                getGameObjectListRecursive(gameObject.transform.parent.gameObject, ref targetGameObjects, 1);\n                                targetGameObjects.Remove(gameObject.transform.parent.gameObject);\n                            }\n                        }\n                        else\n                        {\n                            Debug.Log(\"This action for root objects is supported for Unity3d 5.3.3 and above\");\n                            return;\n                        }\n                    }\n                    else\n                    {\n                        getGameObjectListRecursive(gameObject, ref targetGameObjects, 0);\n                    }\n                }\n                else if (currentEvent.shift)\n                {\n                    if (!showWarning || EditorUtility.DisplayDialog(\"Change visibility\", \"Are you sure you want to turn \" + (gameObject.activeSelf ? \"off\" : \"on\") + \" the visibility of this GameObject and all its children? (You can disable this warning in the settings)\", \"Yes\", \"Cancel\"))\n                    {\n                        getGameObjectListRecursive(gameObject, ref targetGameObjects);           \n                    }\n                }\n                else if (currentEvent.alt) \n                {\n                    if (gameObject.transform.parent != null)\n                    {\n                        if (!showWarning || EditorUtility.DisplayDialog(\"Change visibility\", \"Are you sure you want to turn \" + (gameObject.activeSelf ? \"off\" : \"on\") + \" the visibility this GameObject and its siblings? (You can disable this warning in the settings)\", \"Yes\", \"Cancel\"))\n                        {\n                            getGameObjectListRecursive(gameObject.transform.parent.gameObject, ref targetGameObjects, 1);\n                            targetGameObjects.Remove(gameObject.transform.parent.gameObject);\n                        }\n                    }\n                    else\n                    {\n                        Debug.Log(\"This action for root objects is supported for Unity3d 5.3.3 and above\");\n                        return;\n                    }\n                }\n                else \n                {\n                    if (Selection.Contains(gameObject))\n                    {\n                        targetGameObjects.AddRange(Selection.gameObjects);\n                    }\n                    else\n                    {\n                        getGameObjectListRecursive(gameObject, ref targetGameObjects, 0);\n                    };\n                }\n                \n                setVisibility(targetGameObjects, objectList, !gameObject.activeSelf, currentEvent.control || currentEvent.command);\n                currentEvent.Use();  \n            } \n        }\n\n        // PRIVATE\n        private bool isEditModeVisibile(GameObject gameObject, ObjectList objectList)\n        {\n            return objectList == null ? false : objectList.editModeVisibileObjects.Contains(gameObject);\n        }\n        \n        private bool isEditModeInvisibile(GameObject gameObject, ObjectList objectList)\n        {\n            return objectList == null ? false : objectList.editModeInvisibleObjects.Contains(gameObject);\n        }\n        \n        private void setVisibility(List<GameObject> gameObjects, ObjectList objectList, bool targetVisibility, bool editMode)\n        {\n            if (gameObjects.Count == 0) return;\n\n            if (objectList == null && editMode) objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObjects[0], true);\n            if (objectList != null) Undo.RecordObject(objectList, \"visibility change\");\n            \n            for (int i = gameObjects.Count - 1; i >= 0; i--)\n            {        \n                GameObject curGameObject = gameObjects[i];\n                Undo.RecordObject(curGameObject, \"visibility change\");\n                \n                if (editMode)\n                {\n                    if (!targetVisibility)\n                    {\n                        objectList.editModeVisibileObjects.Remove(curGameObject);        \n                        if (!objectList.editModeInvisibleObjects.Contains(curGameObject))\n                            objectList.editModeInvisibleObjects.Add(curGameObject);\n                    }\n                    else\n                    {\n                        objectList.editModeInvisibleObjects.Remove(curGameObject);                            \n                        if (!objectList.editModeVisibileObjects.Contains(curGameObject))\n                            objectList.editModeVisibileObjects.Add(curGameObject);\n                    }\n                }\n                else if (objectList != null)\n                {\n                    objectList.editModeVisibileObjects.Remove(curGameObject);\n                    objectList.editModeInvisibleObjects.Remove(curGameObject);\n                }\n                \n                curGameObject.SetActive(targetVisibility);\n                EditorUtility.SetDirty(curGameObject);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component/VisibilityComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c73020ec99bb4ad48bcafd323fc4d08a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Component.meta",
    "content": "fileFormatVersion: 2\nguid: 745985dd54264b14faabbb60338e354e\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchyResources.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Hierarchy.Data\n{\n\tpublic enum HierarchyTexture\n\t{\n\t\tHierarchyCheckBoxChecked = 0,\n\t\tHierarchyCheckBoxUnchecked = 1,\n\t\tHierarchyColorButton = 2,\n\t\tHierarchyColorPalette = 3,\n\t\tHierarchyComponentUnknownIcon = 4,\n\t\tHierarchyDragButton = 5,\n\t\tHierarchyErrorIcon = 6,\n\t\tHierarchyLockButton = 7,\n\t\tHierarchyMonoBehaviourIcon = 8,\n\t\tHierarchyPrefabIcon = 9,\n\t\tHierarchyRendererButton = 10,\n\t\tHierarchyRestoreButton = 11,\n\t\tHierarchyTreeMapCurrent = 12,\n\t\tHierarchyTreeMapLast = 13,\n\t\tHierarchyTreeMapLevel = 14,\n\t\tHierarchyTreeMapLevel4 = 15,\n\t\tHierarchyTreeMapObject = 16,\n\t\tHierarchyTrimIcon = 17,\n\t\tHierarchyVisibilityButton = 18,\n\t\tHierarchyVisibilityOffButton = 19,\n        HierarchyTreeMapLine = 20,\n    };\n\n\tpublic enum HierarchyColor\n\t{\n\t\tBackgroundDark,\n\t\tBackground,\n\t\tGray,\n\t\tGrayLight,\n\t\tGrayDark\n\t}\n\n\tpublic class HierarchyResources\n\t{\n\t\t// SINGLETON\n\t\tprivate static HierarchyResources instance;\n\t\tpublic static HierarchyResources getInstance()\n\t\t{\n\t\t\tif (instance == null) instance = new HierarchyResources();\n\t\t\treturn instance;\n\t\t}\n\n\t\t// PRIVATE\n\t\tprivate Dictionary<HierarchyTexture, Texture2D> textures;\n\t\tprivate Dictionary<HierarchyTexture, string> resourcesCommon = new Dictionary<HierarchyTexture, string>()\n\t\t{\n\t\t\t{ HierarchyTexture.HierarchyColorButton, \"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAYAAAArij59AAAAWUlEQVQoFWP8//8/Az7AhE8SJDcYFLBAHakLpIOB2AGIDwDxWiC+DMQMMAUgSR+QABDAaLACmC8cwFIIAs6HKTiAkAOz4HyYFSA7QcABiA8AMYzPwDgUghoAHO8PN+sTbZ4AAAAASUVORK5CYII=\" },\n\t\t\t{ HierarchyTexture.HierarchyColorPalette, \"iVBORw0KGgoAAAANSUhEUgAAAJYAAAA8CAYAAACEhkNqAAADBklEQVR4Ae2dT2sTQRyGZ5uALZaqhxJvevTixasHJR9Mqgc/gDfvkoP4IeqfowcVFPSSBDwYsCBpTY20jTuxC+a3dvKblzk+e1lm5n2n5eFhdguhqRb1FcTrd7cSm3Wtr1d/PdySy092b8ndp7NncnfrzTW5G/b16uN3evdueCGXN+QmRQgkCCBWAg5LOgHE0tnRTBBoiXX6aC+cvdxfqcRxnOeCgJdAS6zq3v2wqEVq5Ir3OI7zXBDwEuja4EYt0Fk9uZRrNAqL8WgpVZzngoCXQOvEisUoUXXj5l+p6jtSeXGSawj8V6zl4y+eVOdyNY/FpsQdAusItB6F/75TLR+L5+9Y8fHIybUOJ+sNgdaJ1byoNxLFe/NC35S4Q2AdgdaJ1Xmw1+osJePlvcWFiYsJtE6si6OsQMBPALH8rEhmEECsDFhE/QS6w+HQnzbJ+ellM5MxnPzMCK9GO5/i36ja9bE31Yp16/jwi9w9GW/L3XCgVz8f6t2rYSyXObFkdBRTBBArRYc1mQBiyegopgggVooOazIBxJLRUUwRQKwUHdZkAoglo6OYIoBYKTqsyQQQS0ZHMUUAsVJ0WJMJIJaMjmKKAGKl6LAmE0AsGR3FFAHEStFhTSbQHQwGcnm7uiR3w7eZ3N15dSJ33+/+kLuzo9dytzNsfQrcv9dXf9Qm3x7ZGf94Gj74wybJiWWAMCxDALHKcGQXQwCxDBCGZQggVhmO7GIIIJYBwrAMAcQqw5FdDAHEMkAYliGAWGU4soshgFgGCMMyBBCrDEd2MQQQywBhWIYAYpXhyC6GAGIZIAzLEECsMhzZxRCoer2e/CVN/cncbJcx3NQ/vrJzR/9yqOdXNjN+ydXodN5fncgYVQf6f8gJk4wfZKK3v5uJjOH1oH9ehxMrAzRRPwHE8rMimUEAsTJgEfUTQCw/K5IZBBArAxZRPwHE8rMimUEAsTJgEfUTQCw/K5IZBBArAxZRPwHE8rMimUEAsTJgEfUTQCw/K5IZBBArAxZRPwHE8rMimUHgD7Cif5j2Lp5yAAAAAElFTkSuQmCC\" },\n\t\t\t{ HierarchyTexture.HierarchyComponentUnknownIcon, \"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABGElEQVQ4EWNgoBAwQvVLAWk1Isy6BVTzDFkdC5Sj9ujZy/3IEsjsD5+/MixdtJChs7XRESoON4QJWSEuNgc7K0NwRBRDbVMbyBKQS0EuBgPiDGBjYxDg4WLwDQxmqG/tghmC24CP334yZM3fziCfN4nBp3sFw+XHrxg42CGGOLt7Qu3G44Jlx64wHLn5iGFpdiCDnAg/Q9a87WDVIEPEhPhRDIAFIoqgjbosg66sGAOIBtkOMgwGuDjYYUwwjdUAkGYQePT2I8P0PWcYMl1MwHxsBN5ArFyxD+ySTBdjbHrBYngNAKnAZztIHq8BNupyIDV4AV4DOjYdBQciPhOwBiJMw8NJeTAmThqvC3DqQpIgNTfCtMJzJQDmf0F9Rh99OwAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyErrorIcon, \"iVBORw0KGgoAAAANSUhEUgAAAAcAAAAQCAYAAADagWXwAAAANklEQVQYGWP8/fs3Ay7AhEsCJE605H+gYhCGA6J1wnXAGAOhkwVmOZBmRGKDmUQ7iLRAIN9OAA9DBxP0TyMiAAAAAElFTkSuQmCC\" },\n\t\t\t{ HierarchyTexture.HierarchyLockButton, \"iVBORw0KGgoAAAANSUhEUgAAAA0AAAAQCAYAAADNo/U5AAAAtklEQVQoFb2QsQ0CMQxFY6Cgp+EmYA4WgDVYhtuFLViBCagoKY/wXxRHXJDCQcGXvuxvf599sRhj+BaLaqCT3osr8SaexKs4Bpsyd4p38RVo6u5J0UWnBoazuBGXOaKp03dv8OSgImDAa0Q0oF/qs3zsOsfL+Pjg2vup7UOV94PU2l4cxBbo40snmpJB352y8SHfnBswvw2Y2ZZmheIrSWVoyv8N/fwQR/0AL9gCfXwJbPJ8cnwCewTKXVfaQ3EAAAAASUVORK5CYII=\" },\n\t\t\t{ HierarchyTexture.HierarchyMonoBehaviourIcon, \"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4EWP8//8/AyWABagZZEIhuYYwkasRpm/UAAaG0TAYDQNQfgClgz+wjEEODQAZqgWLOZX9TgAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyPrefabIcon, \"iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAd0lEQVQoFY2RUQqAMAxDV/GeHkU8ijfzHv3QphIJm7AWtpbtkWTM3L3NapkBuC9Ba4D3j5rpGSDU8bbcd5lzLNmVINpBdhMb5sxsvdIZ4BVLMzYqMayqfcKAUjI6LKA0VG83ADgoQSYfzBepWkZhcFwwm0I5l+weLU0O7oJcg0oAAAAASUVORK5CYII=\" },\n\t\t\t{ HierarchyTexture.HierarchyRendererButton, \"iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQCAYAAAAiYZ4HAAAAdElEQVQoFWP8/v07AwsLCwOxgIlYhTB1JGsAuUUFiGVgJhCgDwCdz3KbgCKYtCOIAXYSKyurIxAzggRwsUFyIIDsBwewCITAxWZg/P37938khfiYICcdGHUSviD68+ePKlD+DihpgCMMn2JkOeSIQxbHyQYAcE0cpIy04qQAAAAASUVORK5CYII=\" },\n\t\t\t{ HierarchyTexture.HierarchyRestoreButton, \"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA3klEQVQ4Ec1RMQ7CMAxMUtj4CSPiATyADzB2QWx8gAlF4geIpTO/YEZIbAz8gxWFuyip3KRR2cDS1fad7dSJttaqkjnnvKS1LpUoU1S+FP53wBobXIFXAGNymfWtwMIdcDfGLAjGgcuGjCC0xlvHjR9AnIFNKyh1C3ENfxJ89gpbihj0DN7X8hmBBvyUh0jIFd6onkEc0wPMB02uUOGU2LRCJ3M/gCfCauQPT4iP/APSVdCiZzoHjsASaICOyT+Igm+Oe4K8hJP3iDsXyIa+AeSlTWSSxukKqT6Y/37AB6sOP8hny1/VAAAAAElFTkSuQmCC\" },\n\t\t\t{ HierarchyTexture.HierarchyTreeMapCurrent, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAQ0lEQVQoFWNgwA+E/wMBUIkwujImdAFi+aMa8YQUCx45dCmUKCFKIzAq36CbQpRGRkZGEbI0QjW9RdY8mgCQQwONDQApiglJmB+fmgAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyTreeMapLast, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAPUlEQVQoFWNgwA+E/wMBUIkwujImdAFi+aMa8YQUCx45dCmUKCFKIzAq36CbwogugMbnBvI50MRGuTQLAQD/rQhHffk54gAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyTreeMapLevel, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAAAJElEQVQoFWNgwA8k/wMBUIkkujImdAFi+aMa8YTUaOCM8MABAI00BE1+cZ4yAAAAAElFTkSuQmCC\" },\n\t\t\t{ HierarchyTexture.HierarchyTreeMapLevel4, \"iVBORw0KGgoAAAANSUhEUgAAADgAAAAQCAYAAABDebxFAAAATklEQVRIDe2SMQoAMAgDpV/w/29t3QWzpnKOGiHmjJgrb1VJcpa1qc3eadaWNTjwd6AQhKB5AryoOSBpD4IyInMBBM0BSXsQlBGZC9YTfL7XEKcUdfHdAAAAAElFTkSuQmCC\" },\n\t\t\t{ HierarchyTexture.HierarchyTreeMapObject, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAYAAAAmlE46AAABnUlEQVQoFdVSTW/aQBR83vX6K9iOkAqmQVUQyoUrUg7cg/qLkTjliDggVfTKZ9rKiT9Q2hjLLsTprMWBWL311Lcar/12Z+fN8xL9N6FUKlXxbQHOCTZmBqTAM/Dr9H6QG8+jPhgM7hqNxnW73b7wPK8mhGBxGKfbb9uX1WoVxnH8FfO8SrwaDoe3rusatu2Srovy0I+e53Zvum6v1/uw2Ww+gfhUJV4WRWEsl0uyrBp1Oh0yTUE/fJ+iICKs6a1Wq8BpTpXIuMLfsEEJgoCiKICqTsfjkegN5i8syrIMH8Sk8feBjFAFFA1KkoTDkyaYIKEByHPOy4ZWFQtd1RSmgA0FNIZIFoZgGCpXybAMKXaoKv5M0v1vprKSxFBQgcEEQwUWCTRrNpvtQNxxedpZvMa72K3X67ZpmTq8gcuY4zivh+Mhm0wm36fT6TjP822VmIdh+LBerxN4cZvNpq1pGvd9/3E0Gn1ZLBbjNE2XEMqrN0eKy5wJf91+v/8ZHbbw3+6jKJojL29O6fpvRKyVoeFZA2Qf9kAGoGX/GH8AjXiXWwSceRAAAAAASUVORK5CYII=\" },\n\t\t\t{ HierarchyTexture.HierarchyTrimIcon, \"iVBORw0KGgoAAAANSUhEUgAAAAcAAAAQCAYAAADagWXwAAAAOUlEQVQYGWP8//8/Ay7AhEsCJD5YJOHOR3cQXALdtSgS6JKMIAFkgG4sigJ0SZBGuAJsknCTaSQJAGHZBh0Iaq7CAAAAAElFTkSuQmCC\" },\n\t\t\t{ HierarchyTexture.HierarchyVisibilityButton, \"iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAABBklEQVQ4EdWTuw4BURCGXRqXXkmvoBXeg5dRU1MpNlHwBBoKUai1GhQKQkmDKKzv3+zIuhQk2/iTz4yZs+PMzIq6rhsJQ7EwiqjGfxQqctM2zOEEF1iCAxX4LA3bJ45twhWkEwxhAAeQbuBAGuw5z9qXKIk+mGY4GVBeuRSMwDTGUcyej5hTtxNY3SQLFVjDHmqQgA2YOjjqwquhjzwEf23iJ1dYk1rT2a4FsFMogVdI6w/njfQrvraWI26t7fCrkIQtmN5a09U00J6dwAaHrfzXw9ZhDa4Btv4zvman9R9BsvU/bYz4Y2vewBSAArRgDtrgBRbgQBmCZx++Wvr8pv4YDe1PeweSfPysEmODwwAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyVisibilityOffButton, \"iVBORw0KGgoAAAANSUhEUgAAABIAAAAQCAYAAAAbBi9cAAABdUlEQVQ4Ea3TvS8EQRjH8dvLHZGoLvQqQaKReKlEp6RA7Q9QafwDGp1EIgqRy3mJhASJSiMaCi4Roj2rOAonkmtEgvX9ze6zVrKh2Sf5zPPM7Mxkd+bOC4Igl0Xks9hEe2S+0TibVlLersCY/Bv2Rs/MnMR2tGKAfIkafJxjET1IDx12pI+sKCOPLdzhAu9QKC+hCFvncrKzzEOLfQp71kJdwpk9JB+hFTYnZ8VCYtIrdR2H0cQ58iza8QSLFQoPbg+dkb57LPHhV9RDmMAe1tCNN5zAop9C81zoRoqRcCRs66R7TEG/2BkovDC5Vi+htS7UucV12HXtIG0J82hiGmUodLsWjxRV69gZ6UCP7ePJp2iDzqAXTVSg+Zu4gS7A1seHrQHdwiq+oNCh72AdDSh2oZ+GDj7eRPWvTvRwmKzFNXxC8YAN+NDVx7dF7fZI28jGCkzqQCf06RrvwgsOor7N/fN/9MFBNuLDDAufNILRsPvTfgP0LsP1SIPKHwAAAABJRU5ErkJggg==\" },\n            { HierarchyTexture.HierarchyTreeMapLine, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAACVBMVEX///8AAAD///9+749PAAAAAnRSTlMAE/ItjOYAAAAWSURBVHgBY6AbYEQAEJcJDhjRZWkJABQbACw6WoebAAAAAElFTkSuQmCC\" },\n        };\n\t\tprivate Dictionary<HierarchyTexture, string> resourcesDark = new Dictionary<HierarchyTexture, string>()\n\t\t{\n\t\t\t{ HierarchyTexture.HierarchyCheckBoxChecked, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABV0lEQVQoFWO0sLD4zwAETEyMDECEF/wDqvwHIoCABUS42wkwlKRKM3CwM4G4OMGPn/8YemY/Zdh56APQIqA1JSnSDDxczAwszIx4MUgNSC3YdSDncXDgtundhz8Mdx7+hLsCpBakB7cOqNJpS18zpFY9ZFi26R1cM4iBofHM5W/AAICouXzzO8PeY5/BHE1lDogglETROHf1G4bSjicMC9e/Zfjz5z9D9+yXYGXOVrwMhtpcKBrBoQoT0dfgYljG9I5h0bq3DM9f/WZ4/PwXAyfQTxlRojAlcBrFRhNdLoaMSIiiPUc/gRUlhwoziAiimA8WR9EIEgn1EmTQVOFg+A+MZxV5doZAN0GwQnQC0yigimmNcgy7jnxikBZnA8YZuhYInwWUgn78+MfAw82MosLNhg+FD+OA1IL0MIHSXs+cpwxfvv1l+PP3P14MUgNSC9LDSG4iBwCgfYRJ3KYMwgAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyCheckBoxUnchecked, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAgElEQVQoFe2SywkAIQxE46cHO/Bu/53YgdaguPsCgpd1hb1uIBjxDSNhTEppyF3GGI7XGkNx8ZAhBIkxinNuK+y9S85ZSilicULkvVdX7k8NA8u7xeLNaf3GZFW4PpzOv3CzqW/LIRGnNVlL9ohRa02Ydw0DC6NZJXu11iNTRNQFcsdGKGm8LNQAAAAASUVORK5CYII=\" },\n\t\t\t{ HierarchyTexture.HierarchyDragButton, \"iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAfElEQVQ4EWM0NjZmoCZgoqZhILNGoIEsaGFoDuRroIkR4t4AKjgJU4RuoMb///8XwCSJoRkZGROA6nAaeMPBwYEYc+BqDh48CHIhHGC48MCBA3BJYhhAF4KCaNSFiMDSoHoYQpMBwgrCLLyxDIoteIwRNgtTxQgsHAa/lwH5tiOYn8m38AAAAABJRU5ErkJggg==\" },\n\t\t};\n\t\tprivate Dictionary<HierarchyTexture, string> resourcesLight = new Dictionary<HierarchyTexture, string>()\n\t\t{\n\t\t\t{ HierarchyTexture.HierarchyCheckBoxChecked, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABOUlEQVQoFY2Sva6CQBCFz4XVQGFjgiZQGKiJnYmFBQVPAo9l7RvQUZAgvAChpqAiGkNDpQLX2bjkkhuMW+zM7pwv85P58X2/x+swxiBJErmTp+s6PJ9PHmd0Hw4HrFYrzGazSYgCj8cDl8sFSZJQIgZN06AoykeIgrIsc+27Ognz+XwSapoGVVUNcdJSS5+besnDMMTxeESapgNMzj+wKArQEOiUZYk8z7mv6zq34hqBURThdDrhfD6jbVsEQcB1tm3DNE3BcMunKn42mw0vKY5j1HWN2+3G+3ddV0gGO8poWRaESJToOA4Wi8UACGcE0ud+v4dhGOj7Huv1GrvdTmhHdlSqiHiehyzLsFwuJ7eJ0QTv9ztUVRUct9vtdvQWD9ISw2j3rtfr1ytHWmJ4qe/dmyxLZPu75L/vGnGpeAWI1gAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyCheckBoxUnchecked, \"iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAjklEQVQoFe2STRJDERCEOwzlApzGbVzVabwboCRp9ezeT5J1ZmGU+Roz1Y+U0hPvEBEopbg9jTEGeu+zLlxjjAghwBhzKmKhtYZSCnLOfEjgvYdz7lLEotZ6svvvFKy1t6IFkGVL100t+iD/hQdDWUe/D4c2qrWui24zWWqE3tu27WPLkaVmenX33lcmfwFMazT7V5IT7wAAAABJRU5ErkJggg==\" },\n\t\t\t{ HierarchyTexture.HierarchyDragButton, \"iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAATklEQVQ4EWM8ceIEAzUBEzUNA5k1aiDlIcqCxYj/WMTwCTEiS7Js27oVmU8xmxFLOhx1IWnBSv0wxGI/SjLAIo9XaDQv4w0eoiQHfxgCAGQPE/BDNfMZAAAAAElFTkSuQmCC\" },\n\t\t};\n\n\t\tprivate Dictionary<HierarchyColor, Color> colors;\n\t\tprivate Dictionary<HierarchyColor, Color> colorsDark = new Dictionary<HierarchyColor, Color>()\n\t\t{\n\t\t\t{ HierarchyColor.BackgroundDark, new Color(0.15f, 0.15f, 0.15f) },\n\t\t\t{ HierarchyColor.Background , new Color(0.22f, 0.22f, 0.22f) },\n\t\t\t{ HierarchyColor.Gray       , new Color(0.6f, 0.6f, 0.6f) },\n\t\t\t{ HierarchyColor.GrayLight  , new Color(0.8f, 0.8f, 0.8f) },\n\t\t\t{ HierarchyColor.GrayDark  , new Color(0.4f, 0.4f, 0.4f) },\n\t\t};\n\t\tprivate Dictionary<HierarchyColor, Color> colorsLight = new Dictionary<HierarchyColor, Color>()\n\t\t{\n\t\t\t{ HierarchyColor.BackgroundDark, new Color(0.88f, 0.88f, 0.88f) },\n\t\t\t{ HierarchyColor.Background , new Color(0.761f, 0.761f, 0.761f) },\n\t\t\t{ HierarchyColor.Gray       , new Color(0.3f, 0.3f, 0.3f) },\n\t\t\t{ HierarchyColor.GrayLight  , new Color(0.1f, 0.1f, 0.1f) },\n\t\t\t{ HierarchyColor.GrayDark  , new Color(0.55f, 0.55f, 0.55f) },\n\t\t};\n\n\t\t// CONSTRUCTOR\n\t\tprivate HierarchyResources()\n\t\t{\n\t\t\ttextures = new Dictionary<HierarchyTexture, Texture2D>();\n\t\t\tforeach (KeyValuePair<HierarchyTexture, string> resourcePair in resourcesCommon)\n\t\t\t{\n\t\t\t\tTexture2D texture = new Texture2D(1,1, TextureFormat.ARGB32, false, false);\n\t\t\t\ttexture.hideFlags = HideFlags.HideAndDontSave;\n\t\t\t\ttexture.LoadImage(Convert.FromBase64String(resourcePair.Value));\n\t\t\t\ttextures.Add(resourcePair.Key, texture);\n\t\t\t}\n\t\t\tDictionary<HierarchyTexture, string> resources = EditorGUIUtility.isProSkin ? resourcesDark : resourcesLight;\n\t\t\tforeach (KeyValuePair<HierarchyTexture, string> resourcePair in resources)\n\t\t\t{\n\t\t\t\tTexture2D texture = new Texture2D(1,1, TextureFormat.ARGB32, false, false);\n\t\t\t\ttexture.hideFlags = HideFlags.HideAndDontSave;\n\t\t\t\ttexture.LoadImage(Convert.FromBase64String(resourcePair.Value));\n\t\t\t\ttextures.Add(resourcePair.Key, texture);\n\t\t\t}\n\t\t\tcolors = EditorGUIUtility.isProSkin ? colorsDark : colorsLight;\n\t\t} \n\n\t\t// PUBLIC\n\t\tpublic Texture2D getTexture(HierarchyTexture textureName) \n\t\t{\n\t\t\treturn textures[textureName];\n\t\t}\n\n\t\tpublic Color getColor(HierarchyColor color)\n\t\t{\n\t\t\treturn colors[color];\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchyResources.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 387ed2783d685b048a858216512aa0c3\ntimeCreated: 1474883135\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettings.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System.Collections;\nusing System.Collections.Generic;\nusing VirtueSky.Hierarchy;\nusing VirtueSky.Hierarchy.Helper;\nusing System.Text;\n\nnamespace VirtueSky.Hierarchy.Data\n{\n    public enum HierarchySetting\n    {\n        TreeMapShow = 0,\n        TreeMapColor = 77,\n        TreeMapEnhanced = 78,\n        TreeMapTransparentBackground = 60,\n\n        MonoBehaviourIconShow = 4,\n        MonoBehaviourIconShowDuringPlayMode = 18,\n        MonoBehaviourIconIgnoreUnityMonobehaviour = 45,\n        MonoBehaviourIconColor = 82,\n\n        SeparatorShow = 8,\n        SeparatorShowRowShading = 50,\n        SeparatorColor = 80,\n        SeparatorEvenRowShadingColor = 79,\n        SeparatorOddRowShadingColor = 81,\n\n        VisibilityShow = 1,\n        VisibilityShowDuringPlayMode = 15,\n\n        LockShow = 2,\n        LockShowDuringPlayMode = 16,\n        LockPreventSelectionOfLockedObjects = 41,\n\n        StaticShow = 12,\n        StaticShowDuringPlayMode = 25,\n\n        ErrorShow = 6,\n        ErrorShowDuringPlayMode = 20,\n        ErrorShowIconOnParent = 27,\n        ErrorShowScriptIsMissing = 28,\n        ErrorShowReferenceIsNull = 29,\n        ErrorShowReferenceIsMissing = 58,\n        ErrorShowStringIsEmpty = 30,\n        ErrorShowMissingEventMethod = 31,\n        ErrorShowWhenTagOrLayerIsUndefined = 32,\n        ErrorIgnoreString = 33,\n        ErrorShowForDisabledComponents = 44,\n        ErrorShowForDisabledGameObjects = 59,\n\n        RendererShow = 7,\n        RendererShowDuringPlayMode = 21,\n\n        PrefabShow = 13,\n        PrefabShowBreakedPrefabsOnly = 51,\n\n        TagAndLayerShow = 5,\n        TagAndLayerShowDuringPlayMode = 19,\n        TagAndLayerSizeShowType = 68,\n        TagAndLayerType = 34,\n        TagAndLayerSizeType = 35,\n        TagAndLayerSizeValuePixel = 36,\n        TagAndLayerAligment = 37,\n        TagAndLayerSizeValueType = 46,\n        TagAndLayerSizeValuePercent = 47,\n        TagAndLayerLabelSize = 48,\n        TagAndLayerTagLabelColor = 66,\n        TagAndLayerLayerLabelColor = 67,\n        TagAndLayerLabelAlpha = 69,\n\n        ColorShow = 9,\n        ColorShowDuringPlayMode = 22,\n\n        GameObjectIconShow = 3,\n        GameObjectIconShowDuringPlayMode = 17,\n        GameObjectIconSize = 63,\n\n        TagIconShow = 14,\n        TagIconShowDuringPlayMode = 26,\n        TagIconListFoldout = 84,\n        TagIconList = 40,\n        TagIconSize = 62,\n\n        LayerIconShow = 85,\n        LayerIconShowDuringPlayMode = 86,\n        LayerIconListFoldout = 87,\n        LayerIconList = 88,\n        LayerIconSize = 89,\n\n        ChildrenCountShow = 11,\n        ChildrenCountShowDuringPlayMode = 24,\n        ChildrenCountLabelSize = 61,\n        ChildrenCountLabelColor = 70,\n\n        VerticesAndTrianglesShow = 53,\n        VerticesAndTrianglesShowDuringPlayMode = 54,\n        VerticesAndTrianglesCalculateTotalCount = 55,\n        VerticesAndTrianglesShowTriangles = 56,\n        VerticesAndTrianglesShowVertices = 64,\n        VerticesAndTrianglesLabelSize = 57,\n        VerticesAndTrianglesVerticesLabelColor = 71,\n        VerticesAndTrianglesTrianglesLabelColor = 72,\n\n        ComponentsShow = 10,\n        ComponentsShowDuringPlayMode = 23,\n        ComponentsIconSize = 65,\n        ComponentsIgnore = 90,\n\n        ComponentsOrder = 38,\n\n        AdditionalIdentation = 39,\n        AdditionalShowHiddenQHierarchyObjectList = 42,\n        AdditionalShowModifierWarning = 43,\n        AdditionalShowObjectListContent = 49,\n        AdditionalHideIconsIfNotFit = 52,\n        AdditionalBackgroundColor = 73,\n        AdditionalActiveColor = 74,\n        AdditionalInactiveColor = 75,\n        AdditionalSpecialColor = 76,\n    }\n\n    public enum HierarchyTagAndLayerType\n    {\n        Always = 0,\n        OnlyIfNotDefault = 1\n    }\n\n    public enum HierarchyTagAndLayerShowType\n    {\n        TagAndLayer = 0,\n        Tag = 1,\n        Layer = 2\n    }\n\n    public enum HierarchyTagAndLayerAligment\n    {\n        Left = 0,\n        Center = 1,\n        Right = 2\n    }\n\n    public enum HierarchyTagAndLayerSizeType\n    {\n        Pixel = 0,\n        Percent = 1\n    }\n\n    public enum HierarchyTagAndLayerLabelSize\n    {\n        Normal = 0,\n        Big = 1,\n        BigIfSpecifiedOnlyTagOrLayer = 2\n    }\n\n    public enum HierarchySize\n    {\n        Normal = 0,\n        Big = 1\n    }\n\n    public enum HierarchySizeAll\n    {\n        Small = 0,\n        Normal = 1,\n        Big = 2\n    }\n\n    public enum HierarchyComponentEnum\n    {\n        LockComponent = 0,\n        VisibilityComponent = 1,\n        StaticComponent = 2,\n        ColorComponent = 3,\n        ErrorComponent = 4,\n        RendererComponent = 5,\n        PrefabComponent = 6,\n        TagAndLayerComponent = 7,\n        GameObjectIconComponent = 8,\n        TagIconComponent = 9,\n        LayerIconComponent = 10,\n        ChildrenCountComponent = 11,\n        VerticesAndTrianglesCount = 12,\n        SeparatorComponent = 1000,\n        TreeMapComponent = 1001,\n        MonoBehaviourIconComponent = 1002,\n        ComponentsComponent = 1003\n    }\n\n    public class TagTexture\n    {\n        public string tag;\n        public Texture2D texture;\n\n        public TagTexture(string tag, Texture2D texture)\n        {\n            this.tag = tag;\n            this.texture = texture;\n        }\n\n        public static List<TagTexture> loadTagTextureList()\n        {\n            List<TagTexture> tagTextureList = new List<TagTexture>();\n            string customTagIcon = HierarchySettings.getInstance().get<string>(HierarchySetting.TagIconList);\n            string[] customTagIconArray = customTagIcon.Split(new char[] { ';' });\n            List<string> tags = new List<string>(UnityEditorInternal.InternalEditorUtility.tags);\n            for (int i = 0; i < customTagIconArray.Length - 1; i += 2)\n            {\n                string tag = customTagIconArray[i];\n                if (!tags.Contains(tag)) continue;\n                string texturePath = customTagIconArray[i + 1];\n\n                Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));\n                if (texture != null)\n                {\n                    TagTexture tagTexture = new TagTexture(tag, texture);\n                    tagTextureList.Add(tagTexture);\n                }\n            }\n\n            return tagTextureList;\n        }\n\n        public static void saveTagTextureList(HierarchySetting setting, List<TagTexture> tagTextureList)\n        {\n            string result = \"\";\n            for (int i = 0; i < tagTextureList.Count; i++)\n                result += tagTextureList[i].tag + \";\" +\n                          AssetDatabase.GetAssetPath(tagTextureList[i].texture.GetInstanceID()) + \";\";\n            HierarchySettings.getInstance().set(setting, result);\n        }\n    }\n\n    public class LayerTexture\n    {\n        public string layer;\n        public Texture2D texture;\n\n        public LayerTexture(string layer, Texture2D texture)\n        {\n            this.layer = layer;\n            this.texture = texture;\n        }\n\n        public static List<LayerTexture> loadLayerTextureList()\n        {\n            List<LayerTexture> layerTextureList = new List<LayerTexture>();\n            string customTagIcon = HierarchySettings.getInstance().get<string>(HierarchySetting.LayerIconList);\n            string[] customLayerIconArray = customTagIcon.Split(new char[] { ';' });\n            List<string> layers = new List<string>(UnityEditorInternal.InternalEditorUtility.layers);\n            for (int i = 0; i < customLayerIconArray.Length - 1; i += 2)\n            {\n                string layer = customLayerIconArray[i];\n                if (!layers.Contains(layer)) continue;\n                string texturePath = customLayerIconArray[i + 1];\n\n                Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));\n                if (texture != null)\n                {\n                    LayerTexture tagTexture = new LayerTexture(layer, texture);\n                    layerTextureList.Add(tagTexture);\n                }\n            }\n\n            return layerTextureList;\n        }\n\n        public static void saveLayerTextureList(HierarchySetting setting, List<LayerTexture> layerTextureList)\n        {\n            string result = \"\";\n            for (int i = 0; i < layerTextureList.Count; i++)\n                result += layerTextureList[i].layer + \";\" +\n                          AssetDatabase.GetAssetPath(layerTextureList[i].texture.GetInstanceID()) + \";\";\n            HierarchySettings.getInstance().set(setting, result);\n        }\n    }\n\n    public delegate void SettingChangedHandler();\n\n    public class HierarchySettings\n    {\n        public bool inited = false;\n        public Rect lastRect;\n        public bool isProSkin;\n        public int indentLevel;\n        public Texture2D checkBoxChecked;\n        public Texture2D checkBoxUnchecked;\n        public Texture2D restoreButtonTexture;\n        public Vector2 scrollPosition = new Vector2();\n        public Color separatorColor;\n        public Color yellowColor;\n        public float totalWidth;\n\n        public HierarchyComponentsOrderList componentsOrderList;\n\n        // CONST\n        private const string PREFS_PREFIX = \"QTools.QHierarchy_\";\n        private const string PREFS_DARK = \"Dark_\";\n        private const string PREFS_LIGHT = \"Light_\";\n        public const string DEFAULT_ORDER = \"0;1;2;3;4;5;6;7;8;9;10;11;12\";\n        public const int DEFAULT_ORDER_COUNT = 13;\n        private const string SETTINGS_FILE_NAME = \"QSettingsObjectAsset\";\n\n        // PRIVATE\n        private HierarchySettingsObject settingsObject;\n        private Dictionary<int, object> defaultSettings = new Dictionary<int, object>();\n        private HashSet<int> skinDependedSettings = new HashSet<int>();\n\n        private Dictionary<int, SettingChangedHandler> settingChangedHandlerList =\n            new Dictionary<int, SettingChangedHandler>();\n\n        // SINGLETON\n        private static HierarchySettings instance;\n\n        public static HierarchySettings getInstance()\n        {\n            if (instance == null) instance = new HierarchySettings();\n            return instance;\n        }\n\n        // CONSTRUCTOR\n        private HierarchySettings()\n        {\n            string[] paths = AssetDatabase.FindAssets(SETTINGS_FILE_NAME);\n            for (int i = 0; i < paths.Length; i++)\n            {\n                settingsObject = (HierarchySettingsObject)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(paths[i]),\n                    typeof(HierarchySettingsObject));\n                if (settingsObject != null) break;\n            }\n\n            if (settingsObject == null)\n            {\n                settingsObject = ScriptableObject.CreateInstance<HierarchySettingsObject>();\n                string path = AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(settingsObject));\n                path = path.Substring(0, path.LastIndexOf(\"/\"));\n                AssetDatabase.CreateAsset(settingsObject, path + \"/\" + SETTINGS_FILE_NAME + \".asset\");\n                AssetDatabase.SaveAssets();\n            }\n\n            initSetting(HierarchySetting.TreeMapShow, true);\n            initSetting(HierarchySetting.TreeMapColor, \"39FFFFFF\", \"905D5D5D\");\n            initSetting(HierarchySetting.TreeMapEnhanced, true);\n            initSetting(HierarchySetting.TreeMapTransparentBackground, true);\n\n            initSetting(HierarchySetting.MonoBehaviourIconShow, true);\n            initSetting(HierarchySetting.MonoBehaviourIconShowDuringPlayMode, true);\n            initSetting(HierarchySetting.MonoBehaviourIconIgnoreUnityMonobehaviour, true);\n            initSetting(HierarchySetting.MonoBehaviourIconColor, \"A01B6DBB\");\n\n            initSetting(HierarchySetting.SeparatorShow, true);\n            initSetting(HierarchySetting.SeparatorShowRowShading, true);\n            initSetting(HierarchySetting.SeparatorColor, \"FF303030\", \"48666666\");\n            initSetting(HierarchySetting.SeparatorEvenRowShadingColor, \"13000000\", \"08000000\");\n            initSetting(HierarchySetting.SeparatorOddRowShadingColor, \"00000000\", \"00FFFFFF\");\n\n            initSetting(HierarchySetting.VisibilityShow, true);\n            initSetting(HierarchySetting.VisibilityShowDuringPlayMode, true);\n\n            initSetting(HierarchySetting.LockShow, true);\n            initSetting(HierarchySetting.LockShowDuringPlayMode, false);\n            initSetting(HierarchySetting.LockPreventSelectionOfLockedObjects, false);\n\n            initSetting(HierarchySetting.StaticShow, true);\n            initSetting(HierarchySetting.StaticShowDuringPlayMode, false);\n\n            initSetting(HierarchySetting.ErrorShow, true);\n            initSetting(HierarchySetting.ErrorShowDuringPlayMode, false);\n            initSetting(HierarchySetting.ErrorShowIconOnParent, false);\n            initSetting(HierarchySetting.ErrorShowScriptIsMissing, true);\n            initSetting(HierarchySetting.ErrorShowReferenceIsNull, false);\n            initSetting(HierarchySetting.ErrorShowReferenceIsMissing, true);\n            initSetting(HierarchySetting.ErrorShowStringIsEmpty, false);\n            initSetting(HierarchySetting.ErrorShowMissingEventMethod, true);\n            initSetting(HierarchySetting.ErrorShowWhenTagOrLayerIsUndefined, true);\n            initSetting(HierarchySetting.ErrorIgnoreString, \"\");\n            initSetting(HierarchySetting.ErrorShowForDisabledComponents, true);\n            initSetting(HierarchySetting.ErrorShowForDisabledGameObjects, true);\n\n            initSetting(HierarchySetting.RendererShow, false);\n            initSetting(HierarchySetting.RendererShowDuringPlayMode, false);\n\n            initSetting(HierarchySetting.PrefabShow, false);\n            initSetting(HierarchySetting.PrefabShowBreakedPrefabsOnly, true);\n\n            initSetting(HierarchySetting.TagAndLayerShow, true);\n            initSetting(HierarchySetting.TagAndLayerShowDuringPlayMode, true);\n            initSetting(HierarchySetting.TagAndLayerSizeShowType, (int)HierarchyTagAndLayerShowType.TagAndLayer);\n            initSetting(HierarchySetting.TagAndLayerType, (int)HierarchyTagAndLayerType.OnlyIfNotDefault);\n            initSetting(HierarchySetting.TagAndLayerAligment, (int)HierarchyTagAndLayerAligment.Left);\n            initSetting(HierarchySetting.TagAndLayerSizeValueType, (int)HierarchyTagAndLayerSizeType.Pixel);\n            initSetting(HierarchySetting.TagAndLayerSizeValuePercent, 0.25f);\n            initSetting(HierarchySetting.TagAndLayerSizeValuePixel, 75);\n            initSetting(HierarchySetting.TagAndLayerLabelSize, (int)HierarchyTagAndLayerLabelSize.Normal);\n            initSetting(HierarchySetting.TagAndLayerTagLabelColor, \"FFCCCCCC\", \"FF333333\");\n            initSetting(HierarchySetting.TagAndLayerLayerLabelColor, \"FFCCCCCC\", \"FF333333\");\n            initSetting(HierarchySetting.TagAndLayerLabelAlpha, 0.35f);\n\n            initSetting(HierarchySetting.ColorShow, true);\n            initSetting(HierarchySetting.ColorShowDuringPlayMode, true);\n\n            initSetting(HierarchySetting.GameObjectIconShow, false);\n            initSetting(HierarchySetting.GameObjectIconShowDuringPlayMode, true);\n            initSetting(HierarchySetting.GameObjectIconSize, (int)HierarchySizeAll.Small);\n\n            initSetting(HierarchySetting.TagIconShow, false);\n            initSetting(HierarchySetting.TagIconShowDuringPlayMode, true);\n            initSetting(HierarchySetting.TagIconListFoldout, false);\n            initSetting(HierarchySetting.TagIconList, \"\");\n            initSetting(HierarchySetting.TagIconSize, (int)HierarchySizeAll.Small);\n\n            initSetting(HierarchySetting.LayerIconShow, false);\n            initSetting(HierarchySetting.LayerIconShowDuringPlayMode, true);\n            initSetting(HierarchySetting.LayerIconListFoldout, false);\n            initSetting(HierarchySetting.LayerIconList, \"\");\n            initSetting(HierarchySetting.LayerIconSize, (int)HierarchySizeAll.Small);\n\n            initSetting(HierarchySetting.ChildrenCountShow, false);\n            initSetting(HierarchySetting.ChildrenCountShowDuringPlayMode, true);\n            initSetting(HierarchySetting.ChildrenCountLabelSize, (int)HierarchySize.Normal);\n            initSetting(HierarchySetting.ChildrenCountLabelColor, \"FFCCCCCC\", \"FF333333\");\n\n            initSetting(HierarchySetting.VerticesAndTrianglesShow, false);\n            initSetting(HierarchySetting.VerticesAndTrianglesShowDuringPlayMode, false);\n            initSetting(HierarchySetting.VerticesAndTrianglesCalculateTotalCount, false);\n            initSetting(HierarchySetting.VerticesAndTrianglesShowTriangles, false);\n            initSetting(HierarchySetting.VerticesAndTrianglesShowVertices, true);\n            initSetting(HierarchySetting.VerticesAndTrianglesLabelSize, (int)HierarchySize.Normal);\n            initSetting(HierarchySetting.VerticesAndTrianglesVerticesLabelColor, \"FFCCCCCC\", \"FF333333\");\n            initSetting(HierarchySetting.VerticesAndTrianglesTrianglesLabelColor, \"FFCCCCCC\", \"FF333333\");\n\n            initSetting(HierarchySetting.ComponentsShow, false);\n            initSetting(HierarchySetting.ComponentsShowDuringPlayMode, false);\n            initSetting(HierarchySetting.ComponentsIconSize, (int)HierarchySizeAll.Small);\n            initSetting(HierarchySetting.ComponentsIgnore, \"\");\n\n            initSetting(HierarchySetting.ComponentsOrder, DEFAULT_ORDER);\n\n            initSetting(HierarchySetting.AdditionalShowObjectListContent, false);\n            initSetting(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList, true);\n            initSetting(HierarchySetting.AdditionalHideIconsIfNotFit, true);\n            initSetting(HierarchySetting.AdditionalIdentation, 0);\n            initSetting(HierarchySetting.AdditionalShowModifierWarning, true);\n\n#if UNITY_2019_1_OR_NEWER\n            initSetting(HierarchySetting.AdditionalBackgroundColor, \"00383838\", \"00CFCFCF\");\n#else\n            initSetting(QSetting.AdditionalBackgroundColor                  , \"00383838\", \"00C2C2C2\");\n#endif\n            initSetting(HierarchySetting.AdditionalActiveColor, \"FFFFFF80\", \"CF363636\");\n            initSetting(HierarchySetting.AdditionalInactiveColor, \"FF4F4F4F\", \"1E000000\");\n            initSetting(HierarchySetting.AdditionalSpecialColor, \"FF2CA8CA\", \"FF1D78D5\");\n        }\n\n        // DESTRUCTOR\n        public void OnDestroy()\n        {\n            skinDependedSettings = null;\n            defaultSettings = null;\n            settingsObject = null;\n            settingChangedHandlerList = null;\n            instance = null;\n        }\n\n        // PUBLIC\n        public T get<T>(HierarchySetting setting)\n        {\n            return (T)settingsObject.get<T>(getSettingName(setting));\n        }\n\n        public Color getColor(HierarchySetting setting)\n        {\n            string stringColor = (string)settingsObject.get<string>(getSettingName(setting));\n            return HierarchyColorUtils.fromString(stringColor);\n        }\n\n        public void setColor(HierarchySetting setting, Color color)\n        {\n            string stringColor = HierarchyColorUtils.toString(color);\n            set(setting, stringColor);\n        }\n\n        public void set<T>(HierarchySetting setting, T value, bool invokeChanger = true)\n        {\n            int settingId = (int)setting;\n            settingsObject.set(getSettingName(setting), value);\n\n            if (invokeChanger && settingChangedHandlerList.ContainsKey(settingId) &&\n                settingChangedHandlerList[settingId] != null)\n                settingChangedHandlerList[settingId].Invoke();\n\n            EditorApplication.RepaintHierarchyWindow();\n        }\n\n        public void addEventListener(HierarchySetting setting, SettingChangedHandler handler)\n        {\n            int settingId = (int)setting;\n\n            if (!settingChangedHandlerList.ContainsKey(settingId))\n                settingChangedHandlerList.Add(settingId, null);\n\n            if (settingChangedHandlerList[settingId] == null)\n                settingChangedHandlerList[settingId] = handler;\n            else\n                settingChangedHandlerList[settingId] += handler;\n        }\n\n        public void removeEventListener(HierarchySetting setting, SettingChangedHandler handler)\n        {\n            int settingId = (int)setting;\n\n            if (settingChangedHandlerList.ContainsKey(settingId) && settingChangedHandlerList[settingId] != null)\n                settingChangedHandlerList[settingId] -= handler;\n        }\n\n        public void restore(HierarchySetting setting)\n        {\n            set(setting, defaultSettings[(int)setting]);\n        }\n\n        // PRIVATE\n        private void initSetting(HierarchySetting setting, object defaultValueDark, object defaultValueLight)\n        {\n            skinDependedSettings.Add((int)setting);\n            initSetting(setting, EditorGUIUtility.isProSkin ? defaultValueDark : defaultValueLight);\n        }\n\n        private void initSetting(HierarchySetting setting, object defaultValue)\n        {\n            string settingName = getSettingName(setting);\n            defaultSettings.Add((int)setting, defaultValue);\n            object value = settingsObject.get(settingName, defaultValue);\n            if (value == null || value.GetType() != defaultValue.GetType())\n            {\n                settingsObject.set(settingName, defaultValue);\n            }\n        }\n\n        private string getSettingName(HierarchySetting setting)\n        {\n            int settingId = (int)setting;\n            string settingName = PREFS_PREFIX;\n            if (skinDependedSettings.Contains(settingId))\n                settingName += EditorGUIUtility.isProSkin ? PREFS_DARK : PREFS_LIGHT;\n            settingName += setting.ToString(\"G\");\n            return settingName.ToString();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettings.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 22eaacdc264c5a84b9f790ff6b99896a\ntimeCreated: 1477924880\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettingsObject.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Hierarchy.Data\n{\n    [System.Serializable]\n    class HierarchySettingsObject: ScriptableObject\n    {\n        [SerializeField] private List<string> settingStringNames  = new List<string>();\n        [SerializeField] private List<string> settingStringValues = new List<string>();\n\n        [SerializeField] private List<string> settingFloatNames   = new List<string>();\n        [SerializeField] private List<float>  settingFloatValues  = new List<float>();\n\n        [SerializeField] private List<string> settingIntNames     = new List<string>();\n        [SerializeField] private List<int>    settingIntValues    = new List<int>();\n\n        [SerializeField] private List<string> settingBoolNames   = new List<string>();\n        [SerializeField] private List<bool>   settingBoolValues  = new List<bool>();\n\n        public void clear()\n        {\n            settingStringNames.Clear();\n            settingStringValues.Clear();\n            settingFloatNames.Clear();\n            settingFloatValues.Clear();\n            settingIntNames.Clear();\n            settingIntValues.Clear();\n            settingBoolNames.Clear();\n            settingBoolValues.Clear();\n        }\n\n        public void set(string settingName, object value)\n        {\n            if (value is bool)\n            {\n                settingBoolValues[settingBoolNames.IndexOf(settingName)] = (bool)value;\n            }\n            else if (value is string)\n            {\n                settingStringValues[settingStringNames.IndexOf(settingName)] = (string)value;\n            }\n            else if (value is float)\n            {\n                settingFloatValues[settingFloatNames.IndexOf(settingName)] = (float)value;\n            }\n            else if (value is int)\n            {\n                settingIntValues[settingIntNames.IndexOf(settingName)] = (int)value;\n            }\n            EditorUtility.SetDirty(this);\n        }\n\n        public object get(string settingName, object defaultValue)\n        {\n            if (defaultValue is bool)\n            {\n                int id = settingBoolNames.IndexOf(settingName);\n                if (id == -1) \n                {\n                    settingBoolNames.Add(settingName);\n                    settingBoolValues.Add((bool)defaultValue);\n                    return defaultValue;\n                }\n                else return settingBoolValues[id];\n            }\n            else if (defaultValue is string)\n            {\n                int id = settingStringNames.IndexOf(settingName);\n                if (id == -1) \n                {\n                    settingStringNames.Add(settingName);\n                    settingStringValues.Add((string)defaultValue);\n                    return defaultValue;\n                }\n                else return settingStringValues[id];\n            }\n            else if (defaultValue is float)\n            {\n                int id = settingFloatNames.IndexOf(settingName);\n                if (id == -1) \n                {\n                    settingFloatNames.Add(settingName);\n                    settingFloatValues.Add((float)defaultValue);\n                    return defaultValue;\n                }\n                else return settingFloatValues[id];\n            }\n            else if (defaultValue is int)\n            {\n                int id = settingIntNames.IndexOf(settingName);\n                if (id == -1) \n                {\n                    settingIntNames.Add(settingName);\n                    settingIntValues.Add((int)defaultValue);\n                    return defaultValue;\n                }\n                else return settingIntValues[id];\n            }\n            return null;\n        }\n        \n        public object get<T>(string settingName)\n        {\n            if (typeof(T) == typeof(bool))\n            {\n                int id = settingBoolNames.IndexOf(settingName);\n                if (id == -1) return null;\n                else return settingBoolValues[id];\n            }\n            else if (typeof(T) == typeof(string))\n            {\n                int id = settingStringNames.IndexOf(settingName);\n                if (id == -1) return null;\n                else return settingStringValues[id];\n            }\n            else if (typeof(T) == typeof(float))\n            {\n                int id = settingFloatNames.IndexOf(settingName);\n                if (id == -1) return null;\n                else return settingFloatValues[id];\n            }\n            else if (typeof(T) == typeof(int))\n            {\n                int id = settingIntNames.IndexOf(settingName);\n                if (id == -1) return null;\n                else return settingIntValues[id];\n            }\n            return null;\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/HierarchySettingsObject.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b9eba1ecab4c43c41869985e270bbe09\ntimeCreated: 1478592157\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/QSettingsObjectAsset.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: b9eba1ecab4c43c41869985e270bbe09, type: 3}\n  m_Name: QSettingsObjectAsset\n  m_EditorClassIdentifier: \n  settingStringNames:\n  - QTools.QHierarchy_Light_TreeMapColor\n  - QTools.QHierarchy_MonoBehaviourIconColor\n  - QTools.QHierarchy_Light_SeparatorColor\n  - QTools.QHierarchy_Light_SeparatorEvenRowShadingColor\n  - QTools.QHierarchy_Light_SeparatorOddRowShadingColor\n  - QTools.QHierarchy_ErrorIgnoreString\n  - QTools.QHierarchy_Light_TagAndLayerTagLabelColor\n  - QTools.QHierarchy_Light_TagAndLayerLayerLabelColor\n  - QTools.QHierarchy_TagIconList\n  - QTools.QHierarchy_LayerIconList\n  - QTools.QHierarchy_Light_ChildrenCountLabelColor\n  - QTools.QHierarchy_Light_VerticesAndTrianglesVerticesLabelColor\n  - QTools.QHierarchy_Light_VerticesAndTrianglesTrianglesLabelColor\n  - QTools.QHierarchy_ComponentsIgnore\n  - QTools.QHierarchy_ComponentsOrder\n  - QTools.QHierarchy_Light_AdditionalBackgroundColor\n  - QTools.QHierarchy_Light_AdditionalActiveColor\n  - QTools.QHierarchy_Light_AdditionalInactiveColor\n  - QTools.QHierarchy_Light_AdditionalSpecialColor\n  - QTools.QHierarchy_Dark_TreeMapColor\n  - QTools.QHierarchy_Dark_SeparatorColor\n  - QTools.QHierarchy_Dark_SeparatorEvenRowShadingColor\n  - QTools.QHierarchy_Dark_SeparatorOddRowShadingColor\n  - QTools.QHierarchy_Dark_TagAndLayerTagLabelColor\n  - QTools.QHierarchy_Dark_TagAndLayerLayerLabelColor\n  - QTools.QHierarchy_Dark_ChildrenCountLabelColor\n  - QTools.QHierarchy_Dark_VerticesAndTrianglesVerticesLabelColor\n  - QTools.QHierarchy_Dark_VerticesAndTrianglesTrianglesLabelColor\n  - QTools.QHierarchy_Dark_AdditionalBackgroundColor\n  - QTools.QHierarchy_Dark_AdditionalActiveColor\n  - QTools.QHierarchy_Dark_AdditionalInactiveColor\n  - QTools.QHierarchy_Dark_AdditionalSpecialColor\n  settingStringValues:\n  - 905D5D5D\n  - A01B6DBB\n  - 48666666\n  - 08000000\n  - 00FFFFFF\n  - \n  - FF333333\n  - FF333333\n  - \n  - \n  - FF333333\n  - FF333333\n  - FF333333\n  - \n  - 0;1;2;3;4;5;6;7;8;9;10;11;12\n  - 00C2C2C2\n  - CF363636\n  - 1E000000\n  - FF1D78D5\n  - E028FF00\n  - FF303030\n  - 13000000\n  - 00000000\n  - FFE41616\n  - FF2B2E2C\n  - FFCCCCCC\n  - FFCCCCCC\n  - FFCCCCCC\n  - 00383838\n  - FFFFFF80\n  - FF4F4F4F\n  - FF2CA8CA\n  settingFloatNames:\n  - QTools.QHierarchy_TagAndLayerSizeValuePercent\n  - QTools.QHierarchy_TagAndLayerLabelAlpha\n  settingFloatValues:\n  - 0.25\n  - 0.35\n  settingIntNames:\n  - QTools.QHierarchy_TagAndLayerSizeShowType\n  - QTools.QHierarchy_TagAndLayerType\n  - QTools.QHierarchy_TagAndLayerAligment\n  - QTools.QHierarchy_TagAndLayerSizeValueType\n  - QTools.QHierarchy_TagAndLayerSizeValuePixel\n  - QTools.QHierarchy_TagAndLayerLabelSize\n  - QTools.QHierarchy_GameObjectIconSize\n  - QTools.QHierarchy_TagIconSize\n  - QTools.QHierarchy_LayerIconSize\n  - QTools.QHierarchy_ChildrenCountLabelSize\n  - QTools.QHierarchy_VerticesAndTrianglesLabelSize\n  - QTools.QHierarchy_ComponentsIconSize\n  - QTools.QHierarchy_AdditionalIdentation\n  settingIntValues: 000000000100000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000\n  settingBoolNames:\n  - QTools.QHierarchy_TreeMapShow\n  - QTools.QHierarchy_TreeMapEnhanced\n  - QTools.QHierarchy_TreeMapTransparentBackground\n  - QTools.QHierarchy_MonoBehaviourIconShow\n  - QTools.QHierarchy_MonoBehaviourIconShowDuringPlayMode\n  - QTools.QHierarchy_MonoBehaviourIconIgnoreUnityMonobehaviour\n  - QTools.QHierarchy_SeparatorShow\n  - QTools.QHierarchy_SeparatorShowRowShading\n  - QTools.QHierarchy_VisibilityShow\n  - QTools.QHierarchy_VisibilityShowDuringPlayMode\n  - QTools.QHierarchy_LockShow\n  - QTools.QHierarchy_LockShowDuringPlayMode\n  - QTools.QHierarchy_LockPreventSelectionOfLockedObjects\n  - QTools.QHierarchy_StaticShow\n  - QTools.QHierarchy_StaticShowDuringPlayMode\n  - QTools.QHierarchy_ErrorShow\n  - QTools.QHierarchy_ErrorShowDuringPlayMode\n  - QTools.QHierarchy_ErrorShowIconOnParent\n  - QTools.QHierarchy_ErrorShowScriptIsMissing\n  - QTools.QHierarchy_ErrorShowReferenceIsNull\n  - QTools.QHierarchy_ErrorShowReferenceIsMissing\n  - QTools.QHierarchy_ErrorShowStringIsEmpty\n  - QTools.QHierarchy_ErrorShowMissingEventMethod\n  - QTools.QHierarchy_ErrorShowWhenTagOrLayerIsUndefined\n  - QTools.QHierarchy_ErrorShowForDisabledComponents\n  - QTools.QHierarchy_ErrorShowForDisabledGameObjects\n  - QTools.QHierarchy_RendererShow\n  - QTools.QHierarchy_RendererShowDuringPlayMode\n  - QTools.QHierarchy_PrefabShow\n  - QTools.QHierarchy_PrefabShowBreakedPrefabsOnly\n  - QTools.QHierarchy_TagAndLayerShow\n  - QTools.QHierarchy_TagAndLayerShowDuringPlayMode\n  - QTools.QHierarchy_ColorShow\n  - QTools.QHierarchy_ColorShowDuringPlayMode\n  - QTools.QHierarchy_GameObjectIconShow\n  - QTools.QHierarchy_GameObjectIconShowDuringPlayMode\n  - QTools.QHierarchy_TagIconShow\n  - QTools.QHierarchy_TagIconShowDuringPlayMode\n  - QTools.QHierarchy_TagIconListFoldout\n  - QTools.QHierarchy_LayerIconShow\n  - QTools.QHierarchy_LayerIconShowDuringPlayMode\n  - QTools.QHierarchy_LayerIconListFoldout\n  - QTools.QHierarchy_ChildrenCountShow\n  - QTools.QHierarchy_ChildrenCountShowDuringPlayMode\n  - QTools.QHierarchy_VerticesAndTrianglesShow\n  - QTools.QHierarchy_VerticesAndTrianglesShowDuringPlayMode\n  - QTools.QHierarchy_VerticesAndTrianglesCalculateTotalCount\n  - QTools.QHierarchy_VerticesAndTrianglesShowTriangles\n  - QTools.QHierarchy_VerticesAndTrianglesShowVertices\n  - QTools.QHierarchy_ComponentsShow\n  - QTools.QHierarchy_ComponentsShowDuringPlayMode\n  - QTools.QHierarchy_AdditionalShowObjectListContent\n  - QTools.QHierarchy_AdditionalShowHiddenQHierarchyObjectList\n  - QTools.QHierarchy_AdditionalHideIconsIfNotFit\n  - QTools.QHierarchy_AdditionalShowModifierWarning\n  settingBoolValues: 01010100010101010101010000000000000101010101010101010000000000010001000100010000010000010000010101010000010101\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data/QSettingsObjectAsset.asset.meta",
    "content": "fileFormatVersion: 2\nguid: 3425b17243bd5c64393e28f9bd687fcb\nNativeFormatImporter:\n  externalObjects: {}\n  mainObjectFileID: 11400000\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Data.meta",
    "content": "fileFormatVersion: 2\nguid: 288b7c4405cbf0a42a20f65be49ee978\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorPickerWindow.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.Helper\n{\n    public delegate void HierarchyColorSelectedHandler(GameObject[] gameObjects, Color color);\n    public delegate void HierarchyColorRemovedHandler(GameObject[] gameObjects);\n\n    public class HierarchyColorPickerWindow: PopupWindowContent \n    {\n        // PRIVATE\n        private GameObject[] gameObjects;\n        private HierarchyColorSelectedHandler colorSelectedHandler;\n        private HierarchyColorRemovedHandler colorRemovedHandler;\n        private Texture2D colorPaletteTexture;\n        private Rect paletteRect;\n\n        // CONSTRUCTOR\n        public HierarchyColorPickerWindow(GameObject[] gameObjects, HierarchyColorSelectedHandler colorSelectedHandler, HierarchyColorRemovedHandler colorRemovedHandler)\n        {\n            this.gameObjects = gameObjects;\n            this.colorSelectedHandler = colorSelectedHandler;\n            this.colorRemovedHandler = colorRemovedHandler;\n\n            colorPaletteTexture = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyColorPalette);\n            paletteRect = new Rect(0, 0, colorPaletteTexture.width, colorPaletteTexture.height);\n        }\n\n        // DESTRUCTOR\n        public override void OnClose()\n        {\n            gameObjects = null;\n            colorSelectedHandler = null;\n            colorRemovedHandler = null; \n        }\n\n        // GUI\n        public override Vector2 GetWindowSize()\n        {\n            return new Vector2(paletteRect.width, paletteRect.height);\n        }\n\n        public override void OnGUI(Rect rect)\n        {\n            GUI.DrawTexture(paletteRect, colorPaletteTexture);\n\n            Vector2 mousePosition = Event.current.mousePosition;\n            if (Event.current.isMouse && Event.current.button == 0 && Event.current.type == EventType.MouseUp && paletteRect.Contains(mousePosition))\n            {\n                Event.current.Use();\n                if (mousePosition.x < 15 && mousePosition.y < 15)\n                {\n                    colorRemovedHandler(gameObjects);\n                }\n                else\n                {\n                    colorSelectedHandler(gameObjects, colorPaletteTexture.GetPixel((int)mousePosition.x, colorPaletteTexture.height - (int)mousePosition.y));\n                }\n                this.editorWindow.Close();\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorPickerWindow.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a7b2618f38024e943bb04bab606dc06e\ntimeCreated: 1475051433\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorUtils.cs",
    "content": "using System;\nusing UnityEngine;\nusing UnityEditor;\n\nnamespace VirtueSky.Hierarchy.Helper\n{\n    public class HierarchyColorUtils\n    {\n        private static Color defaultColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);\n\n        public static void setDefaultColor(Color defaultColor)\n        {\n            HierarchyColorUtils.defaultColor = defaultColor;\n        }\n\n        public static void setColor(Color newColor)\n        {\n            GUI.color = newColor;\n        }\n\n        public static void setColor(Color newColor, float multiColor, float multiAlpha)\n        {\n            newColor.r *= multiColor;\n            newColor.g *= multiColor;\n            newColor.b *= multiColor;\n            newColor.a *= multiAlpha;\n            GUI.color = newColor;\n        }\n\n        public static void clearColor()\n        {\n            GUI.color = defaultColor;\n        }\n\n        public static Color fromString(string color)\n        {\n            return fromInt(Convert.ToUInt32(color,16));\n        }\n        \n        public static string toString(Color color)\n        {\n            uint intColor = toInt(color);\n            return intColor.ToString(\"X8\");\n        }\n\n        public static Color fromInt(uint color)\n        {\n            return new Color(((color >> 16) & 0xFF) / 255.0f,\n                             ((color >>  8) & 0xFF) / 255.0f,\n                             ((color >>  0) & 0xFF) / 255.0f,\n                             ((color >> 24) & 0xFF) / 255.0f);\n        }\n        \n        public static uint toInt(Color color)\n        {\n            return  (uint)((byte)(color.r * 255) << 16) + \n                    (uint)((byte)(color.g * 255) << 8) + \n                    (uint)((byte)(color.b * 255) << 0) + \n                    (uint)((byte)(color.a * 255) << 24);\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyColorUtils.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 70e4d942740a91e45b468c65bbeb78aa\ntimeCreated: 1478071980\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyComponentsOrderList.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing System;\nusing VirtueSky.Hierarchy.Data;\nusing System.Text;\n\nnamespace VirtueSky.Hierarchy.Helper\n{\n    public class HierarchyComponentsOrderList\n    {\n        // PRIVATE\n        private EditorWindow window;\n        private Texture2D dragButton;\n        private bool dragAndDrop = false;\n        private float dragOffset;\n        private int originalDragIndex;\n        private Color backgroundColor;\n\n        // CONSTRUCTOR\n        public HierarchyComponentsOrderList (EditorWindow window)\n        {            \n            this.window = window;\n            dragButton = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyDragButton);\n            backgroundColor = HierarchyResources.getInstance().getColor(HierarchyColor.BackgroundDark);\n        }\n        \n        // PUBLIC\n        public void draw(Rect rect, string[] componentIds)\n        {\n            Event currentEvent = Event.current;\n\n            int currentMouseIndex = Mathf.Clamp(Mathf.RoundToInt((currentEvent.mousePosition.y - dragOffset - rect.y) / 18), 0, componentIds.Length - 1);\n\n            if (dragAndDrop && currentEvent.type == EventType.MouseUp)      \n            {\n                dragAndDrop = false;\n                window.Repaint();\n\n                if (currentMouseIndex != originalDragIndex)\n                {\n                    string newIconOrder = \"\";\n                    for (int j = 0; j < componentIds.Length; j++)\n                    {\n                        if (j == currentMouseIndex) \n                        {\n                            if (j > originalDragIndex)\n                            {\n                                newIconOrder += componentIds[j] + \";\";\n                                newIconOrder += componentIds[originalDragIndex] + \";\";\n                            }\n                            else\n                            {\n                                newIconOrder += componentIds[originalDragIndex] + \";\";\n                                newIconOrder += componentIds[j] + \";\";\n                            }\n                        }\n                        else if (j != originalDragIndex) \n                        {\n                            newIconOrder += componentIds[j] + \";\";\n                        }\n                    }\n                    newIconOrder = newIconOrder.TrimEnd(';');\n                    HierarchySettings.getInstance().set(HierarchySetting.ComponentsOrder, newIconOrder);\n                    componentIds = newIconOrder.Split(';');\n                }\n            }\n            else if (dragAndDrop && currentEvent.type == EventType.MouseDrag)\n            {\n                window.Repaint();\n            }\n\n            for (int i = 0; i < componentIds.Length; i++)\n            {\n                HierarchyComponentEnum type = (HierarchyComponentEnum)int.Parse(componentIds[i]);\n                \n                Rect curRect = new Rect(rect.x, rect.y + 18 * i, rect.width, 16);\n                \n                if (!dragAndDrop && currentEvent.type == EventType.MouseDown && curRect.Contains(currentEvent.mousePosition))\n                {\n                    dragAndDrop = true;\n                    originalDragIndex = i;\n                    dragOffset = currentEvent.mousePosition.y - curRect.y;\n                    Event.current.Use();\n                }\n\n                if (dragAndDrop)\n                {\n                    if (originalDragIndex != i)\n                    {\n                             if (i < originalDragIndex && currentMouseIndex <= i) curRect.y += 18;\n                        else if (i > originalDragIndex && currentMouseIndex >= i) curRect.y -= 18;\n\n                        drawComponentLabel(curRect, type);                \n                    }\n                }\n                else\n                {\n                    drawComponentLabel(curRect, type);                    \n                }\n            }\n\n            if (dragAndDrop)\n            {\n                float curY = currentEvent.mousePosition.y - dragOffset;\n                curY = Mathf.Clamp(curY, rect.y, rect.y + rect.height - 16);\n                drawComponentLabel(new Rect(rect.x, curY, rect.width, rect.height), (HierarchyComponentEnum)int.Parse(componentIds[originalDragIndex]), true);\n            }\n        }\n        \n        // PRIVATE\n        private void drawComponentLabel(Rect rect, HierarchyComponentEnum type, bool withBackground = false)\n        {\n            if (withBackground)\n            {\n                EditorGUI.DrawRect(new Rect(rect.x, rect.y - 2, rect.width, 20), backgroundColor);\n            }\n            GUI.DrawTexture(new Rect(rect.x, rect.y - 2, 20, 20), dragButton);\n            Rect labelRect = new Rect(rect.x + 31, rect.y, rect.width - 20, 16);\n            labelRect.y -= (EditorGUIUtility.singleLineHeight - labelRect.height) * 0.5f;\n            EditorGUI.LabelField(labelRect, getTextWithSpaces(type.ToString()));\n        }\n        \n        private string getTextWithSpaces(string text)\n        {\n            StringBuilder newText = new StringBuilder(text.Length * 2);\n            newText.Append(text[0]);\n            for (int i = 1; i < text.Length; i++)\n            {\n                if (char.IsUpper(text[i]) && text[i - 1] != ' ')                \n                    newText.Append(' ');                \n                newText.Append(text[i]);                \n            }\n            newText.Replace(\" Component\", \"\");\n            return newText.ToString();\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyComponentsOrderList.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bd122316ceb5c1a469ec2d5e9ea9377f\ntimeCreated: 1478011862\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListInspector.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.Data;\n\nnamespace VirtueSky.Hierarchy.Helper\n{\n    [CustomEditor(typeof(ObjectList))]\n    public class HierarchyObjectListInspector : Editor\n    {\n    \tpublic override void OnInspectorGUI()\n    \t{\n    \t\tEditorGUILayout.HelpBox(\"\\nThis is an auto created GameObject that managed by QHierarchy.\\n\\n\" + \n                                    \"It stores references to some GameObjects in the current scene. This object will not be included in the application build.\\n\\n\" + \n                                    \"You can safely remove it, but lock / unlock / visible / etc. states will be reset. Delete this object if you want to remove the QHierarchy.\\n\\n\" +\n                                    \"This object can be hidden if you uncheck \\\"Show QHierarchy GameObject\\\" in the settings of the QHierarchy.\\n\"\n                                    , MessageType.Info, true);\n\n            if (HierarchySettings.getInstance().get<bool>(HierarchySetting.AdditionalShowObjectListContent))\n            {\n                if (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.ExpandWidth(true), GUILayout.Height(20)), \"Hide content\"))\n                {\n                    HierarchySettings.getInstance().set(HierarchySetting.AdditionalShowObjectListContent, false);\n                }\n                base.OnInspectorGUI();\n            }\n            else\n            {\n                if (GUI.Button(EditorGUILayout.GetControlRect(GUILayout.ExpandWidth(true), GUILayout.Height(20)), \"Show content\"))\n                {\n                    HierarchySettings.getInstance().set(HierarchySetting.AdditionalShowObjectListContent, true);\n                }\n            }\n    \t}\n    }\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListInspector.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1182108d9515cea4aa965206552f3c33\ntimeCreated: 1475228494\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEditor;\nusing VirtueSky.Hierarchy.Data;\n#if UNITY_5_3_OR_NEWER\nusing UnityEngine.SceneManagement;\nusing UnityEditor.SceneManagement;\n#endif\n\nnamespace VirtueSky.Hierarchy.Helper\n{\n    public class HierarchyObjectListManager\n    {\n        // CONST\n        private const string HierarchyObjectListName = \"QHierarchyObjectList\";\n\n        // SINGLETON\n        private static HierarchyObjectListManager instance;\n        public static HierarchyObjectListManager getInstance()\n        {\n            if (instance == null) instance = new HierarchyObjectListManager();\n            return instance;\n        }\n\n        // PRIVATE\n        private bool showObjectList;\n        private bool preventSelectionOfLockedObjects;\n        private bool preventSelectionOfLockedObjectsDuringPlayMode;\n        private GameObject lastSelectionGameObject = null;\n        private int lastSelectionCount = 0;\n\n        // CONSTRUCTOR\n        private HierarchyObjectListManager()\n        {\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LockPreventSelectionOfLockedObjects, settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShow              , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.LockShowDuringPlayMode, settingsChanged);\n            settingsChanged();\n        }\n\n        private void settingsChanged()\n        {\n            showObjectList = HierarchySettings.getInstance().get<bool>(HierarchySetting.AdditionalShowHiddenQHierarchyObjectList);\n            preventSelectionOfLockedObjects = HierarchySettings.getInstance().get<bool>(HierarchySetting.LockShow) && HierarchySettings.getInstance().get<bool>(HierarchySetting.LockPreventSelectionOfLockedObjects);\n            preventSelectionOfLockedObjectsDuringPlayMode = preventSelectionOfLockedObjects && HierarchySettings.getInstance().get<bool>(HierarchySetting.LockShowDuringPlayMode);\n        }\n\n        private bool isSelectionChanged()\n        {\n            if (lastSelectionGameObject != Selection.activeGameObject || lastSelectionCount  != Selection.gameObjects.Length)\n            {\n                lastSelectionGameObject = Selection.activeGameObject;\n                lastSelectionCount = Selection.gameObjects.Length;\n                return true;\n            }\n            return false;\n        }\n\n        public void validate()\n        {\n            ObjectList.instances.RemoveAll(item => item == null);\n            foreach (ObjectList objectList in ObjectList.instances)\n                objectList.checkIntegrity();\n            #if UNITY_5_3_OR_NEWER\n            objectListDictionary.Clear();\n            foreach (ObjectList objectList in ObjectList.instances)            \n                objectListDictionary.Add(objectList.gameObject.scene, objectList);\n            #endif\n        }\n\n        #if UNITY_5_3_OR_NEWER\n        private Dictionary<Scene, ObjectList> objectListDictionary = new Dictionary<Scene, ObjectList>();\n        private Scene lastActiveScene;\n        private int lastSceneCount = 0;\n\n        public void update()\n        {\n            try\n            {     \n                List<ObjectList> objectListList = ObjectList.instances;\n                int objectListCount = objectListList.Count;\n                if (objectListCount > 0) \n                {\n                    for (int i = objectListCount - 1; i >= 0; i--)\n                    {\n                        ObjectList objectList = objectListList[i];\n                        Scene objectListScene = objectList.gameObject.scene;\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (objectListDictionary.ContainsKey(objectListScene) && objectListDictionary[objectListScene] == null)\n                            objectListDictionary.Remove(objectListScene);\n\t\t\t\t\t\t\t\n                        if (objectListDictionary.ContainsKey(objectListScene))\n                        {\n                            if (objectListDictionary[objectListScene] != objectList)\n                            {\n                                objectListDictionary[objectListScene].merge(objectList);\n                                GameObject.DestroyImmediate(objectList.gameObject);\n                            }\n                        }\n                        else\n                        {\n                            objectListDictionary.Add(objectListScene, objectList);\n                        }\n                    }\n\n                    foreach (KeyValuePair<Scene, ObjectList> objectListKeyValue in objectListDictionary)\n                    {\n                        ObjectList objectList = objectListKeyValue.Value;\n                        setupObjectList(objectList);\n                        if (( showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy)  > 0)) ||\n                            (!showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy) == 0)))\n                        {\n                            objectList.gameObject.hideFlags ^= HideFlags.HideInHierarchy;      \n                            EditorApplication.DirtyHierarchyWindowSorting();\n                        }\n                    }\n                    \n                    if ((!Application.isPlaying && preventSelectionOfLockedObjects) || \n                        ((Application.isPlaying && preventSelectionOfLockedObjectsDuringPlayMode)) && \n                        isSelectionChanged())\n                    {\n                        GameObject[] selections = Selection.gameObjects;\n                        List<GameObject> actual = new List<GameObject>(selections.Length);\n                        bool found = false;\n                        for (int i = selections.Length - 1; i >= 0; i--)\n                        {\n                            GameObject gameObject = selections[i];\n                            \n                            if (objectListDictionary.ContainsKey(gameObject.scene))\n                            {\n                                bool isLock = objectListDictionary[gameObject.scene].lockedObjects.Contains(selections[i]);\n                                if (!isLock) actual.Add(selections[i]);\n                                else found = true;\n                            }\n                        }\n                        if (found) Selection.objects = actual.ToArray();\n                    }   \n\n                    lastActiveScene = EditorSceneManager.GetActiveScene();\n                    lastSceneCount = SceneManager.loadedSceneCount;\n                }\n            }\n            catch \n            {\n            }\n        }\n\n        public ObjectList getObjectList(GameObject gameObject, bool createIfNotExist = true)\n        { \n            ObjectList objectList = null;\n            objectListDictionary.TryGetValue(gameObject.scene, out objectList);\n            \n            if (objectList == null && createIfNotExist)\n            {         \n                objectList = createObjectList(gameObject);\n                if (gameObject.scene != objectList.gameObject.scene) EditorSceneManager.MoveGameObjectToScene(objectList.gameObject, gameObject.scene);\n                objectListDictionary.Add(gameObject.scene, objectList);\n            }\n\n            return objectList;\n        }\n\n        public bool isSceneChanged()\n        {\n            if (lastActiveScene != EditorSceneManager.GetActiveScene() || lastSceneCount != SceneManager.loadedSceneCount)\n                return true;\n            else \n                return false;\n        }\n\n        #else\n\n        public void update()\n        {\n            try\n            {  \n                List<QObjectList> objectListList = QObjectList.instances;\n                int objectListCount = objectListList.Count;\n                if (objectListCount > 0) \n                {\n                    if (objectListCount > 1)\n                    {\n                        for (int i = objectListCount - 1; i > 0; i--)\n                        {\n                            objectListList[0].merge(objectListList[i]);\n                            GameObject.DestroyImmediate(objectListList[i].gameObject);\n                        }\n                    }\n\n                    QObjectList objectList = QObjectList.instances[0];\n                    setupObjectList(objectList);\n\n                    if (( showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy)  > 0)) ||\n                        (!showObjectList && ((objectList.gameObject.hideFlags & HideFlags.HideInHierarchy) == 0)))\n                    {\n                        objectList.gameObject.hideFlags ^= HideFlags.HideInHierarchy; \n                        EditorApplication.DirtyHierarchyWindowSorting();\n                    }\n\n                    if ((!Application.isPlaying && preventSelectionOfLockedObjects) || \n                        ((Application.isPlaying && preventSelectionOfLockedObjectsDuringPlayMode))\n                        && isSelectionChanged())\n                    {\n                        GameObject[] selections = Selection.gameObjects;\n                        List<GameObject> actual = new List<GameObject>(selections.Length);\n                        bool found = false;\n                        for (int i = selections.Length - 1; i >= 0; i--)\n                        {\n                            GameObject gameObject = selections[i];\n                            \n                            bool isLock = objectList.lockedObjects.Contains(gameObject);                        \n                            if (!isLock) actual.Add(selections[i]);\n                            else found = true;\n                        }\n                        if (found) Selection.objects = actual.ToArray();\n                    }   \n                }\n            }\n            catch \n            {\n            }\n        }\n\n        public QObjectList getObjectList(GameObject gameObject, bool createIfNotExists = false)\n        { \n            List<QObjectList> objectListList = QObjectList.instances;\n            int objectListCount = objectListList.Count;\n            if (objectListCount != 1)\n            {\n                if (objectListCount == 0) \n                {\n                    if (createIfNotExists)\n                    {\n                        createObjectList(gameObject);\n                    }\n                    else\n                    {\n                        return null;\n                    }\n                }\n            }\n                \n            return QObjectList.instances[0];\n        }\n\n        #endif\n\n        private ObjectList createObjectList(GameObject gameObject)\n        {\n            GameObject gameObjectList = new GameObject();\n            gameObjectList.name = HierarchyObjectListName;\n            ObjectList objectList = gameObjectList.AddComponent<ObjectList>();\n            setupObjectList(objectList);\n            return objectList;\n        }\n\n        private void setupObjectList(ObjectList objectList)\n        {\n            if (objectList.tag == \"EditorOnly\") objectList.tag = \"Untagged\";\n            MonoScript monoScript = MonoScript.FromMonoBehaviour(objectList);\n            if (MonoImporter.GetExecutionOrder(monoScript) != -10000)                    \n                MonoImporter.SetExecutionOrder(monoScript, -10000);\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper/HierarchyObjectListManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dac6048cde5fd4d4399d16cc2ffba265\ntimeCreated: 1475228494\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/Helper.meta",
    "content": "fileFormatVersion: 2\nguid: 4874c05321df8604d93643d0c4918324\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/QHierarchyInitializer.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System;\nusing System.Collections.Generic;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy;\nusing UnityEditor.Callbacks;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.phierarchy;\n\nnamespace VirtueSky.Hierarchy\n{\n    [InitializeOnLoad]\n    public class QHierarchyInitializer\n    {\n        private static VHierarchy hierarchy;\n\n        static QHierarchyInitializer()\n        {\n            EditorApplication.update -= update;\n            EditorApplication.update += update;\n\n            EditorApplication.hierarchyWindowItemOnGUI -= hierarchyWindowItemOnGUIHandler;\n            EditorApplication.hierarchyWindowItemOnGUI += hierarchyWindowItemOnGUIHandler;\n\n            EditorApplication.hierarchyChanged -= hierarchyWindowChanged;\n            EditorApplication.hierarchyChanged += hierarchyWindowChanged;\n\n            Undo.undoRedoPerformed -= undoRedoPerformed;\n            Undo.undoRedoPerformed += undoRedoPerformed;\n        }\n\n        static void undoRedoPerformed()\n        {\n            EditorApplication.RepaintHierarchyWindow();\n        }\n\n        static void init()\n        {\n            hierarchy = new VHierarchy();\n        }\n\n        static void update()\n        {\n            if (hierarchy == null) init();\n            HierarchyObjectListManager.getInstance().update();\n        }\n\n        static void hierarchyWindowItemOnGUIHandler(int instanceId, Rect selectionRect)\n        {\n            if (hierarchy == null) init();\n            hierarchy.hierarchyWindowItemOnGUIHandler(instanceId, selectionRect);\n        }\n\n        static void hierarchyWindowChanged()\n        {\n            if (hierarchy == null) init();\n            HierarchyObjectListManager.getInstance().validate();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/QHierarchyInitializer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 91dfc025140434846819647cecf3bd95\ntimeCreated: 1474889436\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/HierarchySettingsWindow.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\nusing VirtueSky.Hierarchy.Data;\nusing System;\nusing VirtueSky.Hierarchy.Helper;\nusing VirtueSky.Hierarchy.HComponent;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Hierarchy.phierarchy\n{\n    public class HierarchySettingsWindow : EditorWindow\n    {\n        // STATIC\n        //[MenuItem (\"Tools/QHierarchy/Settings\")]\t\n//         public static void ShowWindow()\n//         {\n//             EditorWindow window = EditorWindow.GetWindow(typeof(QHierarchySettingsWindow));\n//             window.minSize = new Vector2(350, 50);\n//\n// #if UNITY_4_6 || UNITY_4_7 || UNITY_5_0\n//                 window.title = \"QHierarchy\";\n// #else\n//             window.titleContent = new GUIContent(\"QHierarchy\");\n// #endif\n//         }\n//\n//         // PRIVATE\n//         private bool inited = false;\n//         private Rect lastRect;\n//         private bool isProSkin;\n//         private int indentLevel;\n//         private Texture2D checkBoxChecked;\n//         private Texture2D checkBoxUnchecked;\n//         private Texture2D restoreButtonTexture;\n//         private Vector2 scrollPosition = new Vector2();\n//         private Color separatorColor;\n//         private Color yellowColor;\n//         private float totalWidth;\n//         private QComponentsOrderList componentsOrderList;\n//\n//         // INIT\n//         private void init()\n//         {\n//             inited = true;\n//             isProSkin = EditorGUIUtility.isProSkin;\n//             separatorColor =\n//                 isProSkin ? new Color(0.18f, 0.18f, 0.18f) : new Color(0.59f, 0.59f, 0.59f);\n//             yellowColor =\n//                 isProSkin ? new Color(1.00f, 0.90f, 0.40f) : new Color(0.31f, 0.31f, 0.31f);\n//             checkBoxChecked = QResources.getInstance().getTexture(QTexture.QCheckBoxChecked);\n//             checkBoxUnchecked = QResources.getInstance().getTexture(QTexture.QCheckBoxUnchecked);\n//             restoreButtonTexture = QResources.getInstance().getTexture(QTexture.QRestoreButton);\n//             componentsOrderList = new QComponentsOrderList(this);\n//         }\n//\n//         // GUI\n//         public void OnGUI()\n//         {\n//             EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height),\n//                 GameDataEditor.ColorBackgroundRectWindowSunflower.ToColor());\n//             GUI.contentColor = GameDataEditor.ColorTextContentWindowSunflower.ToColor();\n//             GUI.backgroundColor = GameDataEditor.ColorContentWindowSunflower.ToColor();\n//             if (!inited || isProSkin != EditorGUIUtility.isProSkin)\n//                 init();\n//\n//             indentLevel = 8;\n//             scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);\n//             {\n//                 Rect targetRect = EditorGUILayout.GetControlRect(GUILayout.Height(0));\n//                 if (Event.current.type == EventType.Repaint) totalWidth = targetRect.width + 8;\n//\n//                 this.lastRect = new Rect(0, 1, 0, 0);\n//\n//                 // COMPONENTS\n//                 drawSection(\"COMPONENTS SETTINGS\");\n//                 float sectionStartY = lastRect.y + lastRect.height;\n//\n//                 drawTreeMapComponentSettings();\n//                 drawSeparator();\n//                 drawMonoBehaviourIconComponentSettings();\n//                 drawSeparator();\n//                 drawSeparatorComponentSettings();\n//                 drawSeparator();\n//                 drawVisibilityComponentSettings();\n//                 drawSeparator();\n//                 drawLockComponentSettings();\n//                 drawSeparator();\n//                 drawStaticComponentSettings();\n//                 drawSeparator();\n//                 drawErrorComponentSettings();\n//                 drawSeparator();\n//                 drawRendererComponentSettings();\n//                 drawSeparator();\n//                 drawPrefabComponentSettings();\n//                 drawSeparator();\n//                 drawTagLayerComponentSettings();\n//                 drawSeparator();\n//                 drawColorComponentSettings();\n//                 drawSeparator();\n//                 drawGameObjectIconComponentSettings();\n//                 drawSeparator();\n//                 drawTagIconComponentSettings();\n//                 drawSeparator();\n//                 drawLayerIconComponentSettings();\n//                 drawSeparator();\n//                 drawChildrenCountComponentSettings();\n//                 drawSeparator();\n//                 drawVerticesAndTrianglesCountComponentSettings();\n//                 drawSeparator();\n//                 drawComponentsComponentSettings();\n//                 drawLeftLine(sectionStartY, lastRect.y + lastRect.height, separatorColor);\n//\n//                 // ORDER\n//                 drawSection(\"ORDER OF COMPONENTS\");\n//                 sectionStartY = lastRect.y + lastRect.height;\n//                 drawSpace(8);\n//                 drawOrderSettings();\n//                 drawSpace(6);\n//                 drawLeftLine(sectionStartY, lastRect.y + lastRect.height, separatorColor);\n//\n//                 // ADDITIONAL\n//                 drawSection(\"ADDITIONAL SETTINGS\");\n//                 sectionStartY = lastRect.y + lastRect.height;\n//                 drawSpace(3);\n//                 drawAdditionalSettings();\n//                 drawLeftLine(sectionStartY, lastRect.y + lastRect.height + 4, separatorColor);\n//\n//                 indentLevel -= 1;\n//             }\n//\n//             EditorGUILayout.EndScrollView();\n//         }\n//\n//         // COMPONENTS\n//         private void drawTreeMapComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Hierarchy Tree\", QSetting.TreeMapShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.TreeMapColor);\n//                     QSettings.getInstance().restore(QSetting.TreeMapEnhanced);\n//                     QSettings.getInstance().restore(QSetting.TreeMapTransparentBackground);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5);\n//                 drawSpace(4);\n//                 drawColorPicker(\"Tree color\", QSetting.TreeMapColor);\n//                 drawCheckBoxRight(\"Transparent background\", QSetting.TreeMapTransparentBackground);\n//                 drawCheckBoxRight(\"Enhanced (\\\"Transform Sort\\\" only)\", QSetting.TreeMapEnhanced);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawMonoBehaviourIconComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"MonoBehaviour Icon\", QSetting.MonoBehaviourIconShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.MonoBehaviourIconShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.MonoBehaviourIconColor);\n//                     QSettings.getInstance()\n//                         .restore(QSetting.MonoBehaviourIconIgnoreUnityMonobehaviour);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.MonoBehaviourIconShowDuringPlayMode);\n//                 drawColorPicker(\"Icon color\", QSetting.MonoBehaviourIconColor);\n//                 drawCheckBoxRight(\"Ignore Unity MonoBehaviours\",\n//                     QSetting.MonoBehaviourIconIgnoreUnityMonobehaviour);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawSeparatorComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Separator\", QSetting.SeparatorShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.SeparatorColor);\n//                     QSettings.getInstance().restore(QSetting.SeparatorShowRowShading);\n//                     QSettings.getInstance().restore(QSetting.SeparatorOddRowShadingColor);\n//                     QSettings.getInstance().restore(QSetting.SeparatorEvenRowShadingColor);\n//                 }\n//\n//                 bool rowShading =\n//                     QSettings.getInstance().get<bool>(QSetting.SeparatorShowRowShading);\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * (rowShading ? 4 : 2) + 5);\n//                 drawSpace(4);\n//                 drawColorPicker(\"Separator Color\", QSetting.SeparatorColor);\n//                 drawCheckBoxRight(\"Row shading\", QSetting.SeparatorShowRowShading);\n//                 if (rowShading)\n//                 {\n//                     drawColorPicker(\"Even row shading color\",\n//                         QSetting.SeparatorEvenRowShadingColor);\n//                     drawColorPicker(\"Odd row shading color\", QSetting.SeparatorOddRowShadingColor);\n//                 }\n//\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawVisibilityComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Visibility\", QSetting.VisibilityShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.VisibilityShowDuringPlayMode);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.VisibilityShowDuringPlayMode);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawLockComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Lock\", QSetting.LockShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.LockShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.LockPreventSelectionOfLockedObjects);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.LockShowDuringPlayMode);\n//                 drawCheckBoxRight(\"Prevent selection of locked objects\",\n//                     QSetting.LockPreventSelectionOfLockedObjects);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawStaticComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Static\", QSetting.StaticShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.StaticShowDuringPlayMode);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.StaticShowDuringPlayMode);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawErrorComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Error\", QSetting.ErrorShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.ErrorShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowIconOnParent);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowForDisabledComponents);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowForDisabledGameObjects);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowScriptIsMissing);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowReferenceIsMissing);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowReferenceIsNull);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowStringIsEmpty);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowMissingEventMethod);\n//                     QSettings.getInstance().restore(QSetting.ErrorShowWhenTagOrLayerIsUndefined);\n//                     QSettings.getInstance().restore(QSetting.ErrorIgnoreString);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 12 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.ErrorShowDuringPlayMode);\n//                 drawCheckBoxRight(\"Show error icon up of hierarchy (very slow)\",\n//                     QSetting.ErrorShowIconOnParent);\n//                 drawCheckBoxRight(\"Show error icon for disabled components\",\n//                     QSetting.ErrorShowForDisabledComponents);\n//                 drawCheckBoxRight(\"Show error icon for disabled GameObjects\",\n//                     QSetting.ErrorShowForDisabledGameObjects);\n//                 drawLabel(\"Show error icon for the following:\");\n//                 indentLevel += 16;\n//                 drawCheckBoxRight(\"- script is missing\", QSetting.ErrorShowScriptIsMissing);\n//                 drawCheckBoxRight(\"- reference is missing\", QSetting.ErrorShowReferenceIsMissing);\n//                 drawCheckBoxRight(\"- reference is null\", QSetting.ErrorShowReferenceIsNull);\n//                 drawCheckBoxRight(\"- string is empty\", QSetting.ErrorShowStringIsEmpty);\n//                 drawCheckBoxRight(\"- callback of event is missing (very slow)\",\n//                     QSetting.ErrorShowMissingEventMethod);\n//                 drawCheckBoxRight(\"- tag or layer is undefined\",\n//                     QSetting.ErrorShowWhenTagOrLayerIsUndefined);\n//                 indentLevel -= 16;\n//                 drawTextField(\"Ignore packages/classes\", QSetting.ErrorIgnoreString);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawRendererComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Renderer\", QSetting.RendererShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.RendererShowDuringPlayMode);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.RendererShowDuringPlayMode);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawPrefabComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Prefab\", QSetting.PrefabShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.PrefabShowBreakedPrefabsOnly);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show icon for broken prefabs only\",\n//                     QSetting.PrefabShowBreakedPrefabsOnly);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawTagLayerComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Tag And Layer\", QSetting.TagAndLayerShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerSizeShowType);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerType);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerSizeValueType);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerSizeValuePixel);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerSizeValuePercent);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerAligment);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerLabelSize);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerLabelAlpha);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerTagLabelColor);\n//                     QSettings.getInstance().restore(QSetting.TagAndLayerLayerLabelColor);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 10 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.TagAndLayerShowDuringPlayMode);\n//                 drawEnum(\"Show\", QSetting.TagAndLayerSizeShowType,\n//                     typeof(QHierarchyTagAndLayerShowType));\n//                 drawEnum(\"Show tag and layer\", QSetting.TagAndLayerType,\n//                     typeof(QHierarchyTagAndLayerType));\n//\n//                 QHierarchyTagAndLayerSizeType newTagAndLayerSizeValueType =\n//                     (QHierarchyTagAndLayerSizeType)drawEnum(\"Unit of width\",\n//                         QSetting.TagAndLayerSizeValueType, typeof(QHierarchyTagAndLayerSizeType));\n//\n//                 if (newTagAndLayerSizeValueType == QHierarchyTagAndLayerSizeType.Pixel)\n//                     drawIntSlider(\"Width in pixels\", QSetting.TagAndLayerSizeValuePixel, 5, 250);\n//                 else\n//                     drawFloatSlider(\"Percentage width\", QSetting.TagAndLayerSizeValuePercent, 0,\n//                         0.5f);\n//\n//                 drawEnum(\"Alignment\", QSetting.TagAndLayerAligment,\n//                     typeof(QHierarchyTagAndLayerAligment));\n//                 drawEnum(\"Label size\", QSetting.TagAndLayerLabelSize,\n//                     typeof(QHierarchyTagAndLayerLabelSize));\n//                 drawFloatSlider(\"Label alpha if default\", QSetting.TagAndLayerLabelAlpha, 0, 1.0f);\n//                 drawColorPicker(\"Tag label color\", QSetting.TagAndLayerTagLabelColor);\n//                 drawColorPicker(\"Layer label color\", QSetting.TagAndLayerLayerLabelColor);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawColorComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Color\", QSetting.ColorShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.ColorShowDuringPlayMode);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.ColorShowDuringPlayMode);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawGameObjectIconComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"GameObject Icon\", QSetting.GameObjectIconShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.GameObjectIconShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.GameObjectIconSize);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 2 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.GameObjectIconShowDuringPlayMode);\n//                 drawEnum(\"Icon size\", QSetting.GameObjectIconSize, typeof(QHierarchySizeAll));\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawTagIconComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Tag Icon\", QSetting.TagIconShow))\n//             {\n//                 string[] tags = UnityEditorInternal.InternalEditorUtility.tags;\n//\n//                 bool showTagIconList =\n//                     QSettings.getInstance().get<bool>(QSetting.TagIconListFoldout);\n//\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.TagIconShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.TagIconSize);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width,\n//                     18 * 3 + (showTagIconList ? 18 * tags.Length : 0) + 4 + 5);\n//\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.TagIconShowDuringPlayMode);\n//                 drawEnum(\"Icon size\", QSetting.TagIconSize, typeof(QHierarchySizeAll));\n//                 if (drawFoldout(\"Tag icon list\", QSetting.TagIconListFoldout))\n//                 {\n//                     List<QTagTexture> tagTextureList = QTagTexture.loadTagTextureList();\n//\n//                     bool changed = false;\n//                     for (int i = 0; i < tags.Length; i++)\n//                     {\n//                         string tag = tags[i];\n//                         QTagTexture tagTexture = tagTextureList.Find(t => t.tag == tag);\n//                         Texture2D newTexture = (Texture2D)EditorGUI.ObjectField(\n//                             getControlRect(0, 16, 34 + 16, 6),\n//                             tag, tagTexture == null ? null : tagTexture.texture, typeof(Texture2D),\n//                             false);\n//                         if (newTexture != null && tagTexture == null)\n//                         {\n//                             QTagTexture newTagTexture = new QTagTexture(tag, newTexture);\n//                             tagTextureList.Add(newTagTexture);\n//\n//                             changed = true;\n//                         }\n//                         else if (newTexture == null && tagTexture != null)\n//                         {\n//                             tagTextureList.Remove(tagTexture);\n//                             changed = true;\n//                         }\n//                         else if (tagTexture != null && tagTexture.texture != newTexture)\n//                         {\n//                             tagTexture.texture = newTexture;\n//                             changed = true;\n//                         }\n//\n//                         drawSpace(i == tags.Length - 1 ? 2 : 2);\n//                     }\n//\n//                     if (changed)\n//                     {\n//                         QTagTexture.saveTagTextureList(QSetting.TagIconList, tagTextureList);\n//                         EditorApplication.RepaintHierarchyWindow();\n//                     }\n//                 }\n//\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawLayerIconComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Layer Icon\", QSetting.LayerIconShow))\n//             {\n//                 string[] layers = UnityEditorInternal.InternalEditorUtility.layers;\n//\n//                 bool showLayerIconList =\n//                     QSettings.getInstance().get<bool>(QSetting.LayerIconListFoldout);\n//\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.LayerIconShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.LayerIconSize);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width,\n//                     18 * 3 + (showLayerIconList ? 18 * layers.Length : 0) + 4 + 5);\n//\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.LayerIconShowDuringPlayMode);\n//                 drawEnum(\"Icon size\", QSetting.LayerIconSize, typeof(QHierarchySizeAll));\n//                 if (drawFoldout(\"Layer icon list\", QSetting.LayerIconListFoldout))\n//                 {\n//                     List<QLayerTexture> layerTextureList = QLayerTexture.loadLayerTextureList();\n//\n//                     bool changed = false;\n//                     for (int i = 0; i < layers.Length; i++)\n//                     {\n//                         string layer = layers[i];\n//                         QLayerTexture layerTexture = layerTextureList.Find(t => t.layer == layer);\n//                         Texture2D newTexture = (Texture2D)EditorGUI.ObjectField(\n//                             getControlRect(0, 16, 34 + 16, 6),\n//                             layer, layerTexture == null ? null : layerTexture.texture,\n//                             typeof(Texture2D), false);\n//                         if (newTexture != null && layerTexture == null)\n//                         {\n//                             QLayerTexture newLayerTexture = new QLayerTexture(layer, newTexture);\n//                             layerTextureList.Add(newLayerTexture);\n//\n//                             changed = true;\n//                         }\n//                         else if (newTexture == null && layerTexture != null)\n//                         {\n//                             layerTextureList.Remove(layerTexture);\n//                             changed = true;\n//                         }\n//                         else if (layerTexture != null && layerTexture.texture != newTexture)\n//                         {\n//                             layerTexture.texture = newTexture;\n//                             changed = true;\n//                         }\n//\n//                         drawSpace(i == layers.Length - 1 ? 2 : 2);\n//                     }\n//\n//                     if (changed)\n//                     {\n//                         QLayerTexture.saveLayerTextureList(QSetting.LayerIconList,\n//                             layerTextureList);\n//                         EditorApplication.RepaintHierarchyWindow();\n//                     }\n//                 }\n//\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawChildrenCountComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Children Count\", QSetting.ChildrenCountShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.ChildrenCountShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.ChildrenCountLabelSize);\n//                     QSettings.getInstance().restore(QSetting.ChildrenCountLabelColor);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.ChildrenCountShowDuringPlayMode);\n//                 drawEnum(\"Label size\", QSetting.ChildrenCountLabelSize, typeof(QHierarchySize));\n//                 drawColorPicker(\"Label color\", QSetting.ChildrenCountLabelColor);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawVerticesAndTrianglesCountComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Vertices And Triangles Count\",\n//                     QSetting.VerticesAndTrianglesShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance()\n//                         .restore(QSetting.VerticesAndTrianglesShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.VerticesAndTrianglesShowVertices);\n//                     QSettings.getInstance().restore(QSetting.VerticesAndTrianglesShowTriangles);\n//                     QSettings.getInstance()\n//                         .restore(QSetting.VerticesAndTrianglesCalculateTotalCount);\n//                     QSettings.getInstance().restore(QSetting.VerticesAndTrianglesLabelSize);\n//                     QSettings.getInstance()\n//                         .restore(QSetting.VerticesAndTrianglesVerticesLabelColor);\n//                     QSettings.getInstance()\n//                         .restore(QSetting.VerticesAndTrianglesTrianglesLabelColor);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 7 + 5);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.VerticesAndTrianglesShowDuringPlayMode);\n//                 if (drawCheckBoxRight(\"Show vertices count\",\n//                         QSetting.VerticesAndTrianglesShowVertices))\n//                 {\n//                     if (QSettings.getInstance()\n//                             .get<bool>(QSetting.VerticesAndTrianglesShowVertices) == false &&\n//                         QSettings.getInstance()\n//                             .get<bool>(QSetting.VerticesAndTrianglesShowTriangles) == false)\n//                         QSettings.getInstance()\n//                             .set(QSetting.VerticesAndTrianglesShowTriangles, true);\n//                 }\n//\n//                 if (drawCheckBoxRight(\"Show triangles count (very slow)\",\n//                         QSetting.VerticesAndTrianglesShowTriangles))\n//                 {\n//                     if (QSettings.getInstance()\n//                             .get<bool>(QSetting.VerticesAndTrianglesShowVertices) == false &&\n//                         QSettings.getInstance()\n//                             .get<bool>(QSetting.VerticesAndTrianglesShowTriangles) == false)\n//                         QSettings.getInstance()\n//                             .set(QSetting.VerticesAndTrianglesShowVertices, true);\n//                 }\n//\n//                 drawCheckBoxRight(\"Calculate the count including children (very slow)\",\n//                     QSetting.VerticesAndTrianglesCalculateTotalCount);\n//                 drawEnum(\"Label size\", QSetting.VerticesAndTrianglesLabelSize,\n//                     typeof(QHierarchySize));\n//                 drawColorPicker(\"Vertices label color\",\n//                     QSetting.VerticesAndTrianglesVerticesLabelColor);\n//                 drawColorPicker(\"Triangles label color\",\n//                     QSetting.VerticesAndTrianglesTrianglesLabelColor);\n//                 drawSpace(1);\n//             }\n//         }\n//\n//         private void drawComponentsComponentSettings()\n//         {\n//             if (drawComponentCheckBox(\"Components\", QSetting.ComponentsShow))\n//             {\n//                 Rect rect = getControlRect(0, 0);\n//                 if (drawRestore())\n//                 {\n//                     QSettings.getInstance().restore(QSetting.ComponentsShowDuringPlayMode);\n//                     QSettings.getInstance().restore(QSetting.ComponentsIconSize);\n//                 }\n//\n//                 drawBackground(rect.x, rect.y, rect.width, 18 * 3 + 6);\n//                 drawSpace(4);\n//                 drawCheckBoxRight(\"Show component during play mode\",\n//                     QSetting.ComponentsShowDuringPlayMode);\n//                 drawEnum(\"Icon size\", QSetting.ComponentsIconSize, typeof(QHierarchySizeAll));\n//                 drawTextField(\"Ignore packages/classes\", QSetting.ComponentsIgnore);\n//                 drawSpace(2);\n//             }\n//         }\n//\n//         // COMPONENTS ORDER\n//         private void drawOrderSettings()\n//         {\n//             if (drawRestore())\n//             {\n//                 QSettings.getInstance().restore(QSetting.ComponentsOrder);\n//             }\n//\n//             indentLevel += 4;\n//\n//             string componentOrder = QSettings.getInstance().get<string>(QSetting.ComponentsOrder);\n//             string[] componentIds = componentOrder.Split(';');\n//\n//             Rect rect = getControlRect(position.width, 17 * componentIds.Length + 10, 0, 0);\n//             if (componentsOrderList == null)\n//                 componentsOrderList = new QComponentsOrderList(this);\n//             componentsOrderList.draw(rect, componentIds);\n//\n//             indentLevel -= 4;\n//         }\n//\n//         // ADDITIONAL SETTINGS\n//         private void drawAdditionalSettings()\n//         {\n//             if (drawRestore())\n//             {\n//                 QSettings.getInstance().restore(QSetting.AdditionalShowHiddenQHierarchyObjectList);\n//                 QSettings.getInstance().restore(QSetting.AdditionalHideIconsIfNotFit);\n//                 QSettings.getInstance().restore(QSetting.AdditionalIdentation);\n//                 QSettings.getInstance().restore(QSetting.AdditionalShowModifierWarning);\n//                 QSettings.getInstance().restore(QSetting.AdditionalBackgroundColor);\n//                 QSettings.getInstance().restore(QSetting.AdditionalActiveColor);\n//                 QSettings.getInstance().restore(QSetting.AdditionalInactiveColor);\n//                 QSettings.getInstance().restore(QSetting.AdditionalSpecialColor);\n//             }\n//\n//             drawSpace(4);\n//             drawCheckBoxRight(\"Show QHierarchyObjectList GameObject\",\n//                 QSetting.AdditionalShowHiddenQHierarchyObjectList);\n//             drawCheckBoxRight(\"Hide icons if not fit\", QSetting.AdditionalHideIconsIfNotFit);\n//             drawIntSlider(\"Right indent\", QSetting.AdditionalIdentation, 0, 500);\n//             drawCheckBoxRight(\"Show warning when using modifiers + click\",\n//                 QSetting.AdditionalShowModifierWarning);\n//             drawColorPicker(\"Background color\", QSetting.AdditionalBackgroundColor);\n//             drawColorPicker(\"Active color\", QSetting.AdditionalActiveColor);\n//             drawColorPicker(\"Inactive color\", QSetting.AdditionalInactiveColor);\n//             drawColorPicker(\"Special color\", QSetting.AdditionalSpecialColor);\n//             drawSpace(1);\n//         }\n//\n//         // PRIVATE\n//         private void drawSection(string title)\n//         {\n//             Rect rect = getControlRect(0, 24, -3, 0);\n//             rect.width *= 2;\n//             rect.x = 0;\n//             GUI.Box(rect, \"\");\n//\n//             drawLeftLine(rect.y, rect.y + 24, yellowColor);\n//\n//             rect.x = lastRect.x + 8;\n//             rect.y += 4;\n//             EditorGUI.LabelField(rect, title);\n//         }\n//\n//         private void drawSeparator(int spaceBefore = 0, int spaceAfter = 0, int height = 1)\n//         {\n//             if (spaceBefore > 0) drawSpace(spaceBefore);\n//             Rect rect = getControlRect(0, height, 0, 0);\n//             rect.width += 8;\n//             EditorGUI.DrawRect(rect, separatorColor);\n//             if (spaceAfter > 0) drawSpace(spaceAfter);\n//         }\n//\n//         private bool drawComponentCheckBox(string label, QSetting setting)\n//         {\n//             indentLevel += 8;\n//\n//             Rect rect = getControlRect(0, 28, 0, 0);\n//\n//             float rectWidth = rect.width;\n//             bool isChecked = QSettings.getInstance().get<bool>(setting);\n//\n//             rect.x -= 1;\n//             rect.y += 7;\n//             rect.width = 14;\n//             rect.height = 14;\n//\n//             if (GUI.Button(rect, isChecked ? checkBoxChecked : checkBoxUnchecked, GUIStyle.none))\n//             {\n//                 QSettings.getInstance().set(setting, !isChecked);\n//             }\n//\n//             rect.x += 14 + 10;\n//             rect.width = rectWidth - 14 - 8;\n//             rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n//             rect.height = EditorGUIUtility.singleLineHeight;\n//\n//             EditorGUI.LabelField(rect, label);\n//\n//             indentLevel -= 8;\n//\n//             return isChecked;\n//         }\n//\n//         private bool drawCheckBoxRight(string label, QSetting setting)\n//         {\n//             Rect rect = getControlRect(0, 18, 34, 6);\n//             bool result = false;\n//             bool isChecked = QSettings.getInstance().get<bool>(setting);\n//\n//             float tempX = rect.x;\n//             rect.x += rect.width - 14;\n//             rect.y += 1;\n//             rect.width = 14;\n//             rect.height = 14;\n//\n//             if (GUI.Button(rect, isChecked ? checkBoxChecked : checkBoxUnchecked, GUIStyle.none))\n//             {\n//                 QSettings.getInstance().set(setting, !isChecked);\n//                 result = true;\n//             }\n//\n//             rect.width = rect.x - tempX - 4;\n//             rect.x = tempX;\n//             rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n//             rect.height = EditorGUIUtility.singleLineHeight;\n//\n//             EditorGUI.LabelField(rect, label);\n//\n//             return result;\n//         }\n//\n//         private void drawSpace(int value)\n//         {\n//             getControlRect(0, value, 0, 0);\n//         }\n//\n//         private void drawBackground(float x, float y, float width, float height)\n//         {\n//             EditorGUI.DrawRect(new Rect(x, y, width, height), separatorColor);\n//         }\n//\n//         private void drawLeftLine(float fromY, float toY, Color color, float width = 0)\n//         {\n//             EditorGUI.DrawRect(new Rect(0, fromY, width == 0 ? indentLevel : width, toY - fromY),\n//                 color);\n//         }\n//\n//         private Rect getControlRect(float width, float height, float addIndent = 0,\n//             float remWidth = 0)\n//         {\n//             EditorGUILayout.GetControlRect(false, height, GUIStyle.none,\n//                 GUILayout.ExpandWidth(true));\n//             Rect rect = new Rect(indentLevel + addIndent, lastRect.y + lastRect.height,\n//                 (width == 0 ? totalWidth - indentLevel - addIndent - remWidth : width), height);\n//             lastRect = rect;\n//             return rect;\n//         }\n//\n//         private bool drawRestore()\n//         {\n//             if (GUI.Button(new Rect(lastRect.x + lastRect.width - 16 - 5, lastRect.y - 20, 16, 16),\n//                     restoreButtonTexture, GUIStyle.none))\n//             {\n//                 if (EditorUtility.DisplayDialog(\"Restore\", \"Restore default settings?\", \"Ok\",\n//                         \"Cancel\"))\n//                 {\n//                     return true;\n//                 }\n//             }\n//\n//             return false;\n//         }\n//\n//         // GUI COMPONENTS\n//         private void drawLabel(string label)\n//         {\n//             Rect rect = getControlRect(0, 16, 34, 6);\n//             rect.y -= (EditorGUIUtility.singleLineHeight - rect.height) * 0.5f;\n//             EditorGUI.LabelField(rect, label);\n//             drawSpace(2);\n//         }\n//\n//         private void drawTextField(string label, QSetting setting)\n//         {\n//             string currentValue = QSettings.getInstance().get<string>(setting);\n//             string newValue =\n//                 EditorGUI.TextField(getControlRect(0, 16, 34, 6), label, currentValue);\n//             if (!currentValue.Equals(newValue)) QSettings.getInstance().set(setting, newValue);\n//             drawSpace(2);\n//         }\n//\n//         private bool drawFoldout(string label, QSetting setting)\n//         {\n// #if UNITY_2019_1_OR_NEWER\n//             Rect foldoutRect = getControlRect(0, 16, 19, 6);\n// #else\n//                 Rect foldoutRect = getControlRect(0, 16, 22, 6);\n// #endif\n//             bool foldoutValue = QSettings.getInstance().get<bool>(setting);\n//             bool newFoldoutValue = EditorGUI.Foldout(foldoutRect, foldoutValue, label);\n//             if (foldoutValue != newFoldoutValue)\n//                 QSettings.getInstance().set(setting, newFoldoutValue);\n//             drawSpace(2);\n//             return newFoldoutValue;\n//         }\n//\n//         private void drawColorPicker(string label, QSetting setting)\n//         {\n//             Color currentColor = QSettings.getInstance().getColor(setting);\n//             Color newColor =\n//                 EditorGUI.ColorField(getControlRect(0, 16, 34, 6), label, currentColor);\n//             if (!currentColor.Equals(newColor)) QSettings.getInstance().setColor(setting, newColor);\n//             drawSpace(2);\n//         }\n//\n//         private Enum drawEnum(string label, QSetting setting, Type enumType)\n//         {\n//             Enum currentEnum =\n//                 (Enum)Enum.ToObject(enumType, QSettings.getInstance().get<int>(setting));\n//             Enum newEnumValue;\n//             if (!(newEnumValue =\n//                     EditorGUI.EnumPopup(getControlRect(0, 16, 34, 6), label, currentEnum))\n//                 .Equals(currentEnum))\n//                 QSettings.getInstance().set(setting, (int)(object)newEnumValue);\n//             drawSpace(2);\n//             return newEnumValue;\n//         }\n//\n//         private void drawIntSlider(string label, QSetting setting, int minValue, int maxValue)\n//         {\n//             Rect rect = getControlRect(0, 16, 34, 4);\n//             int currentValue = QSettings.getInstance().get<int>(setting);\n//             int newValue = EditorGUI.IntSlider(rect, label, currentValue, minValue, maxValue);\n//             if (currentValue != newValue) QSettings.getInstance().set(setting, newValue);\n//             drawSpace(2);\n//         }\n//\n//         private void drawFloatSlider(string label, QSetting setting, float minValue, float maxValue)\n//         {\n//             Rect rect = getControlRect(0, 16, 34, 4);\n//             float currentValue = QSettings.getInstance().get<float>(setting);\n//             float newValue = EditorGUI.Slider(rect, label, currentValue, minValue, maxValue);\n//             if (currentValue != newValue) QSettings.getInstance().set(setting, newValue);\n//             drawSpace(2);\n//         }\n    }\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/HierarchySettingsWindow.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 311dd60af7f888a4ea46d48565c35ed1\ntimeCreated: 1474888502\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/VHierarchy.cs",
    "content": "using UnityEngine;\nusing UnityEditor;\nusing System;\nusing System.Collections.Generic;\nusing VirtueSky.Hierarchy.HComponent;\nusing VirtueSky.Hierarchy.HComponent.Base;\nusing VirtueSky.Hierarchy.Data;\nusing VirtueSky.Hierarchy.Helper;\nusing System.Reflection;\n\nnamespace VirtueSky.Hierarchy.phierarchy\n{\n    public class VHierarchy\n    {\n        // PRIVATE\n        private HashSet<int> errorHandled = new HashSet<int>();      \n        private Dictionary<int, BaseComponent> componentDictionary;          \n        private List<BaseComponent> preComponents;\n        private List<BaseComponent> orderedComponents;\n        private bool hideIconsIfThereIsNoFreeSpace;\n        private int indentation;\n        private Texture2D trimIcon;\n        private Color backgroundColor;\n        private Color inactiveColor;\n\n        // CONSTRUCTOR\n        public VHierarchy ()\n        {           \n            componentDictionary = new Dictionary<int, BaseComponent>();\n            componentDictionary.Add((int)HierarchyComponentEnum.LockComponent             , new LockComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.VisibilityComponent       , new VisibilityComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.StaticComponent           , new StaticComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.RendererComponent         , new RendererComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.TagAndLayerComponent      , new TagLayerComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.GameObjectIconComponent   , new GameObjectIconComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.ErrorComponent            , new ErrorComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.TagIconComponent          , new TagIconComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.LayerIconComponent        , new LayerIconComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.ColorComponent            , new ColorComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.ComponentsComponent       , new ComponentsComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.ChildrenCountComponent    , new ChildrenCountComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.PrefabComponent           , new PrefabComponent());\n            componentDictionary.Add((int)HierarchyComponentEnum.VerticesAndTrianglesCount , new VerticesAndTrianglesCountComponent());\n\n            preComponents = new List<BaseComponent>();\n            preComponents.Add(new MonoBehaviorIconComponent());\n            preComponents.Add(new TreeMapComponent());\n            preComponents.Add(new SeparatorComponent());\n\n            orderedComponents = new List<BaseComponent>();\n\n            trimIcon = HierarchyResources.getInstance().getTexture(HierarchyTexture.HierarchyTrimIcon);\n\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalIdentation             , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.ComponentsOrder                  , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalHideIconsIfNotFit      , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalBackgroundColor        , settingsChanged);\n            HierarchySettings.getInstance().addEventListener(HierarchySetting.AdditionalInactiveColor          , settingsChanged);\n            settingsChanged();\n        }\n         \n        // PRIVATE\n        private void settingsChanged()\n        {\n            string componentOrder = HierarchySettings.getInstance().get<string>(HierarchySetting.ComponentsOrder);\n            string[] componentIds = componentOrder.Split(';');\n            if (componentIds.Length != HierarchySettings.DEFAULT_ORDER_COUNT) \n            {\n                HierarchySettings.getInstance().set(HierarchySetting.ComponentsOrder, HierarchySettings.DEFAULT_ORDER, false);\n                componentIds = HierarchySettings.DEFAULT_ORDER.Split(';');\n            }\n\n            orderedComponents.Clear(); \n            for (int i = 0; i < componentIds.Length; i++)                \n                orderedComponents.Add(componentDictionary[int.Parse(componentIds[i])]);\n            orderedComponents.Add(componentDictionary[(int)HierarchyComponentEnum.ComponentsComponent]);\n\n            indentation                     = HierarchySettings.getInstance().get<int>(HierarchySetting.AdditionalIdentation);\n            hideIconsIfThereIsNoFreeSpace   = HierarchySettings.getInstance().get<bool>(HierarchySetting.AdditionalHideIconsIfNotFit);\n            backgroundColor                 = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalBackgroundColor);\n            inactiveColor                   = HierarchySettings.getInstance().getColor(HierarchySetting.AdditionalInactiveColor);\n        } \n\n        public void hierarchyWindowItemOnGUIHandler(int instanceId, Rect selectionRect)\n        {\n            try\n            {\n                HierarchyColorUtils.setDefaultColor(GUI.color);\n\n                GameObject gameObject = (GameObject)EditorUtility.InstanceIDToObject(instanceId);\n                if (gameObject == null) return;\n\n                Rect curRect = new Rect(selectionRect);\n                curRect.width = 16;\n                curRect.x += selectionRect.width - indentation;\n\n                float gameObjectNameWidth = hideIconsIfThereIsNoFreeSpace ? GUI.skin.label.CalcSize(new GUIContent(gameObject.name)).x : 0;\n\n                ObjectList objectList = HierarchyObjectListManager.getInstance().getObjectList(gameObject, false);\n\n                drawComponents(orderedComponents, selectionRect, ref curRect, gameObject, objectList, true, hideIconsIfThereIsNoFreeSpace ? selectionRect.x + gameObjectNameWidth + 7 : 0);    \n\n                errorHandled.Remove(instanceId);\n            }\n            catch (Exception exception)\n            {\n                if (errorHandled.Add(instanceId))\n                {\n                    Debug.LogError(exception.ToString());\n                }\n            }\n        }\n\n        private void drawComponents(List<BaseComponent> components, Rect selectionRect, ref Rect rect, GameObject gameObject, ObjectList objectList, bool drawBackground = false, float minX = 50)\n        {\n            if (Event.current.type == EventType.Repaint)\n            {\n                int toComponent = components.Count;\n                LayoutStatus layoutStatus = LayoutStatus.Success;\n                for (int i = 0, n = toComponent; i < n; i++)\n                {\n                    BaseComponent component = components[i];\n                    if (component.isEnabled())\n                    {\n                        layoutStatus = component.layout(gameObject, objectList, selectionRect, ref rect, rect.x - minX);\n                        if (layoutStatus != LayoutStatus.Success)\n                        {\n                            toComponent = layoutStatus == LayoutStatus.Failed ? i : i + 1;\n                            rect.x -= 7;\n\n                            break;\n                        }\n                    }\n                    else\n                    {\n                        component.disabledHandler(gameObject, objectList);\n                    }\n                } \n\n                if (drawBackground)\n                {\n                    if (backgroundColor.a != 0)\n                    {\n                        rect.width = selectionRect.x + selectionRect.width - rect.x /*- indentation*/;\n                        EditorGUI.DrawRect(rect, backgroundColor);\n                    }\n                    drawComponents(preComponents    , selectionRect, ref rect, gameObject, objectList);\n                }\n\n                for (int i = 0, n = toComponent; i < n; i++)\n                {\n                    BaseComponent component = components[i];\n                    if (component.isEnabled())\n                    {\n                        component.draw(gameObject, objectList, selectionRect);\n                    }\n                }\n\n                if (layoutStatus != LayoutStatus.Success)\n                {\n                    rect.width = 7;\n                    HierarchyColorUtils.setColor(inactiveColor);\n                    GUI.DrawTexture(rect, trimIcon);\n                    HierarchyColorUtils.clearColor();\n                }\n            }\n            else if (Event.current.isMouse)\n            {\n                for (int i = 0, n = components.Count; i < n; i++)\n                {\n                    BaseComponent component = components[i];\n                    if (component.isEnabled())\n                    {\n                        if (component.layout(gameObject, objectList, selectionRect, ref rect, rect.x - minX) != LayoutStatus.Failed)\n                        {\n                            component.eventHandler(gameObject, objectList, Event.current);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/VHierarchy/VHierarchy.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4b7e0353599820d438074ea45a106853\ntimeCreated: 1474888198\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts/VHierarchy.meta",
    "content": "fileFormatVersion: 2\nguid: cc4f43cb5bd4bf546a9edf40a361f0f5\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor/Scripts.meta",
    "content": "fileFormatVersion: 2\nguid: a37008235cb5c0c4b9ca8932a016d63c\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 325ffd836cb52054d9f615250b95398d\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchy.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Hierarchy\n{\n    [ExecuteInEditMode]\n    [EditorIcon(\"icon_hierarchy\"), HideMonoScript]\n    public class HeaderHierarchy : MonoBehaviour\n    {\n        #region Variables\n\n        public enum TextAlignment\n        {\n            Left,\n            Center\n        }\n\n        [TitleColor(\"Text\", CustomColor.Gold, CustomColor.Aqua)] [SerializeField]\n        public bool customText;\n\n        [ShowIf(nameof(customText)), SerializeField]\n        public Color32 textColor = InspectorUtility.textNormalColor;\n\n        [Space] [SerializeField] public FontStyle textStyle = FontStyle.BoldAndItalic;\n\n        [SerializeField] public TextAlignment textAlignment = TextAlignment.Left;\n\n        [TitleColor(\"Highlight\", CustomColor.Coral, CustomColor.Lime)] [Space, SerializeField]\n        public bool customHighlight;\n\n        [ShowIf(nameof(customHighlight)), SerializeField]\n        public Color32 highlightColor = InspectorUtility.cyanColor;\n\n        #endregion\n    } // class end\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchy.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e3036e8f2fe4f8e4bb99b79fe6ebdf01\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 422b56a3ea31444cd82f5ee33cbd31d4, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchyIcon.cs",
    "content": "#if UNITY_EDITOR\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.Hierarchy\n{\n    [InitializeOnLoad]\n    public class HeaderHierarchyIcon\n    {\n        #region Static Variables\n\n        // icons\n        private static string assetPath = \"/VirtueSky/Hierarchy/Icons\";\n        private static Texture2D icon_HierarchyHighlight;\n\n        #endregion\n\n        //----------------------------------------------------------------------------------------------------\n\n        #region Contructors\n\n        static HeaderHierarchyIcon()\n        {\n            // subscribe to inspector updates\n            EditorApplication.hierarchyWindowItemOnGUI += EditorApplication_hierarchyWindowItemOnGUI;\n        }\n\n        #endregion\n\n        //----------------------------------------------------------------------------------------------------\n\n        #region Private Functions\n\n        private static void CreateHierarchyIcon_Highlight()\n        {\n            icon_HierarchyHighlight = FileExtension.FindAssetWithPath<Texture2D>(\"HierarchyHighlight.png\", assetPath);\n        }\n\n        private static void EditorApplication_hierarchyWindowItemOnGUI(int instanceID, Rect position)\n        {\n            // check for valid draw\n            if (Event.current.type != EventType.Repaint)\n            {\n                return;\n            }\n\n            GameObject gameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject;\n            if (gameObject != null)\n            {\n                HeaderHierarchy component = gameObject.GetComponent<HeaderHierarchy>();\n                if (component != null)\n                {\n                    // cache values\n                    int hierarchyPixelHeight = 16;\n                    bool isSelected = Selection.instanceIDs.Contains(instanceID);\n                    bool isActive = component.isActiveAndEnabled;\n                    Color32 defaultContentColor = GUI.contentColor;\n                    Color32 textColor;\n                    Color32 backgroundColor;\n\n                    if (isActive || isSelected)\n                    {\n                        // text\n                        if (component.customText)\n                        {\n                            textColor = component.textColor;\n                        }\n                        else\n                        {\n                            textColor = InspectorUtility.textNormalColor;\n                        }\n                    }\n                    else\n                    {\n                        // text\n                        if (component.customText)\n                        {\n                            textColor = (Color)component.textColor * 0.6f;\n                        }\n                        else\n                        {\n                            textColor = InspectorUtility.textDisabledColor;\n                        }\n                    }\n\n                    // draw background\n                    if (isSelected)\n                    {\n                        backgroundColor = InspectorUtility.backgroundActiveColor;\n                    }\n                    else\n                    {\n                        backgroundColor = InspectorUtility.backgroundNormalColorLight;\n                    }\n\n                    Rect backgroundPosition = new Rect(position.xMin, position.yMin, position.width + hierarchyPixelHeight, position.height);\n                    EditorGUI.DrawRect(backgroundPosition, backgroundColor);\n\n                    // check icon exists\n                    if (!icon_HierarchyHighlight)\n                    {\n                        CreateHierarchyIcon_Highlight();\n                    }\n\n                    // draw highlight\n                    if (component.customHighlight)\n                    {\n                        GUI.contentColor = component.highlightColor;\n                        Rect iconPosition = new Rect(position.xMin, position.yMin, icon_HierarchyHighlight.width, icon_HierarchyHighlight.height);\n                        GUIContent iconGUIContent = new GUIContent(icon_HierarchyHighlight);\n                        EditorGUI.LabelField(iconPosition, iconGUIContent);\n                        GUI.contentColor = defaultContentColor;\n                    }\n\n                    // draw text\n                    GUIStyle hierarchyText = new GUIStyle() { };\n                    hierarchyText.normal = new GUIStyleState() { textColor = textColor };\n                    hierarchyText.fontStyle = component.textStyle;\n                    int offsetX;\n                    if (component.textAlignment == HeaderHierarchy.TextAlignment.Center)\n                    {\n                        hierarchyText.alignment = TextAnchor.MiddleCenter;\n                        offsetX = 0;\n                    }\n                    else\n                    {\n                        hierarchyText.alignment = TextAnchor.MiddleLeft;\n                        offsetX = hierarchyPixelHeight + 2;\n                    }\n\n                    Rect textOffset = new Rect(position.xMin + offsetX, position.yMin, position.width, position.height);\n                    EditorGUI.LabelField(textOffset, component.name, hierarchyText);\n                }\n            }\n        }\n\n        #endregion\n    } // class end\n}\n#endif"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/HeaderHierarchyIcon.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 051786f9cab235441ac9f2abcea3bd94\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/HierarchyHeader.asmdef",
    "content": "{\n  \"name\": \"HierarchyHeader\",\n  \"rootNamespace\": \"\",\n  \"references\": [\n    \"GUID:324caed91501a9c47a04ebfd87b68794\",\n    \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n    \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n  ],\n  \"includePlatforms\": [],\n  \"excludePlatforms\": [],\n  \"allowUnsafeCode\": false,\n  \"overrideReferences\": false,\n  \"precompiledReferences\": [],\n  \"autoReferenced\": true,\n  \"defineConstraints\": [],\n  \"versionDefines\": [],\n  \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/HierarchyHeader.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: d4acae227198a6b4395e2c4a4b0b6a56\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/InspectorUtility.cs",
    "content": "using UnityEngine;\n#if UNITY_EDITOR\nusing UnityEditor;\n#endif\n\n\nnamespace VirtueSky.Hierarchy\n{\n    public static class InspectorUtility\n    {\n        #region Static Variables\n\n        // blank\n        public static readonly Color32 blankColor = new Color32(000, 000, 000, 000);\n        public static readonly Color32 cyanColor = new Color32(000, 179, 223, 255);\n        public static readonly Color32 yellowColor = new Color32(223, 179, 000, 255);\n\n        // background\n        public static readonly Color32 backgroundNormalColorLight = new Color32(056, 056, 056, 255);\n        public static readonly Color32 backgroundNormalColor = new Color32(051, 051, 051, 255);\n        public static readonly Color32 backgroundNormalColorDark = new Color32(045, 045, 045, 255);\n        public static readonly Color32 backgroundActiveColor = new Color32(044, 093, 135, 255);\n        public static readonly Color32 backgroundHoverColor = new Color32(056, 056, 056, 255);\n        public static readonly Color32 backgroundShadowColor = new Color32(042, 042, 042, 255);\n        public static readonly Color32 backgroundSeperatorColor = new Color32(035, 035, 035, 255);\n\n        // selected\n        public static readonly Color32 buttonSelectedColor = new Color32(128, 179, 223, 255);\n\n        // button - normal, hover, active\n        public static readonly Color32 buttonHoverColor = new Color32(099, 099, 099, 255);\n        public static readonly Color32 buttonHoverBorderColor = new Color32(028, 028, 028, 255);\n        public static readonly Color32 buttonActiveColor = new Color32(000, 128, 223, 255);\n        public static readonly Color32 buttonActiveBorderColor = new Color32(010, 010, 010, 255);\n\n        // text\n        public static readonly Color32 textNormalColor = new Color32(179, 179, 179, 255);\n        public static readonly Color32 textDisabledColor = new Color32(113, 113, 113, 255);\n\n        #endregion\n\n        //----------------------------------------------------------------------------------------------------\n\n        #region Helper Functions\n\n#if UNITY_EDITOR\n        public static void DrawInspectorLine(Color32 lineColor)\n        {\n            GUIStyle horizontalLine = new GUIStyle\n            {\n                normal = { background = EditorGUIUtility.whiteTexture },\n                margin = new RectOffset(0, 0, 4, 4),\n                fixedHeight = 1\n            };\n\n            Color defaultGUIColor = GUI.color;\n            GUI.color = lineColor;\n            EditorGUILayout.Space();\n            GUILayout.Box(GUIContent.none, horizontalLine);\n            GUI.color = defaultGUIColor;\n        }\n#endif\n\n        public static Texture2D CreateTexture(int width, int height, int border, bool isRounded, Color32 backgroundColor, Color32 borderColor)\n        {\n            Color[] pixels = new Color[width * height];\n            int pixelIndex = 0;\n\n            if (isRounded)\n            {\n                for (int i = 0; i < width; i++)\n                {\n                    for (int j = 0; j < height; j++)\n                    {\n                        // if at corner add corner color\n                        if ((i < border || i >= width - border) && (j < border || j >= width - border))\n                        {\n                            pixels[pixelIndex] = blankColor;\n                        }\n                        // otherwise if on border... \n                        else if ((i < border || i >= width - border || j < border || j >= width - border)\n                                 || ((i < border * 2 || i >= width - border * 2) && (j < border * 2 || j >= width - border * 2)))\n                        {\n                            // ... add border color\n                            pixels[pixelIndex] = borderColor;\n                        }\n                        else\n                        {\n                            // ... otherwise add background color\n                            pixels[pixelIndex] = backgroundColor;\n                        }\n\n                        pixelIndex++;\n                    }\n                }\n            }\n            else\n            {\n                for (int i = 0; i < width; i++)\n                {\n                    for (int j = 0; j < height; j++)\n                    {\n                        // if on border... \n                        if (i < border || i >= width - border || j < border || j >= width - border)\n                        {\n                            // ... add border color\n                            pixels[pixelIndex] = borderColor;\n                        }\n                        else\n                        {\n                            // ... otherwise add background color\n                            pixels[pixelIndex] = backgroundColor;\n                        }\n\n                        pixelIndex++;\n                    }\n                }\n            }\n\n            Texture2D result = new Texture2D(width, height);\n            result.SetPixels(pixels);\n            result.Apply();\n            return result;\n        }\n\n        public static Texture2D TintTexture(Texture2D texture2D, Color tint)\n        {\n            // null check\n            if (!texture2D)\n            {\n                return null;\n            }\n\n            int width = texture2D.width;\n            int height = texture2D.height;\n            Color[] pixels = new Color[width * height];\n            int pixelIndex = 0;\n\n            for (int i = 0; i < width; i++)\n            {\n                for (int j = 0; j < height; j++)\n                {\n                    pixels[pixelIndex] = texture2D.GetPixel(j, i) * tint;\n                    pixelIndex++;\n                }\n            }\n\n            Texture2D result = new Texture2D(width, height);\n            result.SetPixels(pixels);\n            result.Apply();\n            return result;\n        }\n\n        public static Texture2D AddBorderToTexture(Texture2D texture2D, Color borderColor, int borderThickness)\n        {\n            // null check\n            if (!texture2D)\n            {\n                return null;\n            }\n\n            int width = texture2D.width;\n            int height = texture2D.height;\n            Color[] pixels = new Color[width * height];\n            int pixelIndex = 0;\n\n            for (int i = 0; i < width; i++)\n            {\n                for (int j = 0; j < height; j++)\n                {\n                    // if on border... \n                    if (i < borderThickness || i >= width - borderThickness || j < borderThickness || j >= width - borderThickness)\n                    {\n                        // ... add border color\n                        pixels[pixelIndex] = borderColor;\n                    }\n                    else\n                    {\n                        // ... otherwise get pixel color\n                        pixels[pixelIndex] = pixels[pixelIndex] = texture2D.GetPixel(j, i);\n                    }\n\n                    pixelIndex++;\n                }\n            }\n\n            Texture2D result = new Texture2D(width, height);\n            result.SetPixels(pixels);\n            result.Apply();\n            return result;\n        }\n\n        #endregion\n\n        //----------------------------------------------------------------------------------------------------\n\n        #region Custom Button Styles\n\n        public static GUIStyle Style_DefaultButton()\n        {\n            return new GUIStyle(GUI.skin.button);\n        }\n\n        public static GUIStyle Style_Button()\n        {\n            GUIStyle buttonStyle = new GUIStyle();\n\n            buttonStyle.fontSize = 9;\n            buttonStyle.alignment = TextAnchor.MiddleCenter;\n            buttonStyle.normal.textColor = textNormalColor;\n            buttonStyle.hover.textColor = textNormalColor;\n            buttonStyle.active.textColor = textNormalColor;\n            buttonStyle.normal.background = CreateTexture(20, 20, 1, true, blankColor, blankColor);\n            buttonStyle.hover.background = CreateTexture(20, 20, 1, true, buttonHoverColor, buttonHoverBorderColor);\n            buttonStyle.active.background = CreateTexture(20, 20, 1, true, buttonActiveColor, buttonActiveBorderColor);\n\n            return buttonStyle;\n        }\n\n        public static GUIStyle Style_ImageButton(Texture2D normalTexture, int outline = 0)\n        {\n            Color32 hover = new Color32(223, 223, 223, 255);\n            Color32 active = new Color32(079, 128, 179, 255);\n\n            if (0 < outline)\n            {\n                return Style_ImageButton(normalTexture, active, outline);\n            }\n            else\n            {\n                return Style_ImageButton(normalTexture, hover, active);\n            }\n        }\n\n        public static GUIStyle Style_ImageButton(Texture2D normalTexture, Color activeTint, int thickness)\n        {\n            GUIStyle buttonStyle = new GUIStyle();\n            Texture2D hoverTexture = AddBorderToTexture(normalTexture, activeTint, thickness);\n            Texture2D activeTexture = TintTexture(normalTexture, activeTint);\n\n            buttonStyle.normal.background = normalTexture;\n            buttonStyle.hover.background = hoverTexture;\n            buttonStyle.active.background = activeTexture;\n\n            return buttonStyle;\n        }\n\n        public static GUIStyle Style_ImageButton(Texture2D normalTexture, Color hoverTint, Color activeTint)\n        {\n            GUIStyle buttonStyle = new GUIStyle();\n            Texture2D hoverTexture = TintTexture(normalTexture, hoverTint);\n            Texture2D activeTexture = TintTexture(normalTexture, activeTint);\n\n            buttonStyle.normal.background = normalTexture;\n            buttonStyle.hover.background = hoverTexture;\n            buttonStyle.active.background = activeTexture;\n\n            return buttonStyle;\n        }\n\n        public static GUIStyle Style_StealthButton()\n        {\n            GUIStyle buttonStyle = new GUIStyle();\n            buttonStyle.fontSize = 10;\n            buttonStyle.normal.textColor = Color.grey;\n\n            return buttonStyle;\n        }\n\n        #endregion\n    } // class end\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy/InspectorUtility.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1abe08dca56cc5a42920f170820c5760\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/FolderHierarchy.meta",
    "content": "fileFormatVersion: 2\nguid: 643b5b480bb19af43a78bf179abb87fc\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Icons/HierarchyHighlight.png.meta",
    "content": "fileFormatVersion: 2\nguid: 01b0134cecf44934f86df7ffd52f333d\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Icons.meta",
    "content": "fileFormatVersion: 2\nguid: b64e9c6185a69634386d98c3cf6888cf\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Scripts/HierarchyRuntime.asmdef",
    "content": "{\n    \"name\": \"HierarchyRuntime\",\n    \"rootNamespace\": \"\",\n    \"references\": [],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Scripts/HierarchyRuntime.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 211f9e8f16a5ff644946a29c81bedf42\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Scripts/ObjectList.cs",
    "content": "﻿using UnityEngine;\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\n#if UNITY_EDITOR\nusing UnityEditor;\n#endif\n\nnamespace VirtueSky.Hierarchy\n{\n    [ExecuteInEditMode]\n    [AddComponentMenu(\"\")]\n    public class ObjectList : MonoBehaviour, ISerializationCallbackReceiver\n    {\n        public static List<ObjectList> instances = new List<ObjectList>();\n\n        public List<GameObject> lockedObjects = new List<GameObject>();\n        public List<GameObject> editModeVisibileObjects = new List<GameObject>();\n        public List<GameObject> editModeInvisibleObjects = new List<GameObject>();\n        public List<GameObject> wireframeHiddenObjects = new List<GameObject>();\n        public Dictionary<GameObject, Color> gameObjectColor = new Dictionary<GameObject, Color>();\n        public List<GameObject> gameObjectColorKeys = new List<GameObject>();\n        public List<Color> gameObjectColorValues = new List<Color>();\n\n        public void Awake()\n        {\n            checkIntegrity();\n\n            foreach (GameObject editModeGameObject in editModeVisibileObjects)\n                editModeGameObject.SetActive(!Application.isPlaying);\n\n            foreach (GameObject editModeGameObject in editModeInvisibleObjects)\n                editModeGameObject.SetActive(Application.isPlaying);\n\n            if (!Application.isEditor && Application.isPlaying)\n            {\n                instances.Remove(this);\n                DestroyImmediate(gameObject);\n                return;\n            }\n\n            instances.RemoveAll(item => item == null);\n            if (!instances.Contains(this)) instances.Add(this);\n        }\n\n        public void OnEnable()\n        {\n            if (!instances.Contains(this)) instances.Add(this);\n\n#if UNITY_EDITOR\n            foreach (GameObject wireframeGameObject in wireframeHiddenObjects)\n            {\n                Renderer renderer = wireframeGameObject.GetComponent<Renderer>();\n                if (renderer != null)\n                {\n#if UNITY_5_5_OR_NEWER\n                    EditorUtility.SetSelectedRenderState(renderer, EditorSelectedRenderState.Hidden);\n#else\n                    EditorUtility.SetSelectedWireframeHidden(renderer, true);\n#endif\n                }\n            }\n#endif\n        }\n\n        public void OnDestroy()\n        {\n            if (!Application.isPlaying)\n            {\n                checkIntegrity();\n\n                foreach (GameObject gameObject in editModeVisibileObjects)\n                    gameObject.SetActive(false);\n\n                foreach (GameObject gameObject in editModeInvisibleObjects)\n                    gameObject.SetActive(true);\n\n                foreach (GameObject gameObject in lockedObjects)\n                    gameObject.hideFlags &= ~HideFlags.NotEditable;\n\n                instances.Remove(this);\n            }\n        }\n\n        public void merge(ObjectList anotherInstance)\n        {\n            for (int i = anotherInstance.lockedObjects.Count - 1; i >= 0; i--)\n            {\n                if (!lockedObjects.Contains(anotherInstance.lockedObjects[i]))\n                    lockedObjects.Add(anotherInstance.lockedObjects[i]);\n            }\n\n            for (int i = anotherInstance.editModeVisibileObjects.Count - 1; i >= 0; i--)\n            {\n                if (!editModeVisibileObjects.Contains(anotherInstance.editModeVisibileObjects[i]))\n                    editModeVisibileObjects.Add(anotherInstance.editModeVisibileObjects[i]);\n            }\n\n            for (int i = anotherInstance.editModeInvisibleObjects.Count - 1; i >= 0; i--)\n            {\n                if (!editModeInvisibleObjects.Contains(anotherInstance.editModeInvisibleObjects[i]))\n                    editModeInvisibleObjects.Add(anotherInstance.editModeInvisibleObjects[i]);\n            }\n\n            for (int i = anotherInstance.wireframeHiddenObjects.Count - 1; i >= 0; i--)\n            {\n                if (!wireframeHiddenObjects.Contains(anotherInstance.wireframeHiddenObjects[i]))\n                    wireframeHiddenObjects.Add(anotherInstance.wireframeHiddenObjects[i]);\n            }\n\n            for (int i = anotherInstance.gameObjectColorKeys.Count - 1; i >= 0; i--)\n            {\n                if (!gameObjectColorKeys.Contains(anotherInstance.gameObjectColorKeys[i]))\n                {\n                    gameObjectColorKeys.Add(anotherInstance.gameObjectColorKeys[i]);\n                    gameObjectColorValues.Add(anotherInstance.gameObjectColorValues[i]);\n                    gameObjectColor.Add(anotherInstance.gameObjectColorKeys[i],\n                        anotherInstance.gameObjectColorValues[i]);\n                }\n            }\n        }\n\n        public void checkIntegrity()\n        {\n            lockedObjects.RemoveAll(item => item == null);\n            editModeVisibileObjects.RemoveAll(item => item == null);\n            editModeInvisibleObjects.RemoveAll(item => item == null);\n            wireframeHiddenObjects.RemoveAll(item => item == null);\n\n            for (int i = gameObjectColorKeys.Count - 1; i >= 0; i--)\n            {\n                if (gameObjectColorKeys[i] == null)\n                {\n                    gameObjectColorKeys.RemoveAt(i);\n                    gameObjectColorValues.RemoveAt(i);\n                }\n            }\n\n            OnAfterDeserialize();\n        }\n\n        public void OnBeforeSerialize()\n        {\n            gameObjectColorKeys.Clear();\n            gameObjectColorValues.Clear();\n            foreach (KeyValuePair<GameObject, Color> pair in gameObjectColor)\n            {\n                gameObjectColorKeys.Add(pair.Key);\n                gameObjectColorValues.Add(pair.Value);\n            }\n        }\n\n        public void OnAfterDeserialize()\n        {\n            gameObjectColor.Clear();\n            for (int i = 0; i < gameObjectColorKeys.Count; i++)\n                gameObjectColor.Add(gameObjectColorKeys[i], gameObjectColorValues[i]);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Hierarchy/Scripts/ObjectList.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 845e8bd83609e3549af5a311ad811681\ntimeCreated: 1475506195\nlicenseType: Store\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: -10000\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy/Scripts.meta",
    "content": "fileFormatVersion: 2\nguid: 7de9a0dec5e15f64fa8b3c79974355f0\nfolderAsset: yes\ntimeCreated: 1515657177\nlicenseType: Store\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Hierarchy.meta",
    "content": "fileFormatVersion: 2\nguid: b66613caeea30044ab544ffda293c903\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap/Editor/IapSettingEditor.cs",
    "content": "﻿#if VIRTUESKY_IAP\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.Iap\n{\n    [CustomEditor(typeof(IapSetting), true)]\n    public class IapSettingEditor : Editor\n    {\n        private IapSetting _iapSetting;\n        private SerializedProperty _skusData;\n        private SerializedProperty _products;\n        private SerializedProperty _isValidatePurchase;\n        private SerializedProperty _isCustomValidatePurchase;\n        private SerializedProperty _googlePlayStoreKey;\n\n        void Initialize()\n        {\n            _iapSetting = target as IapSetting;\n            _skusData = serializedObject.FindProperty(\"skusData\");\n            _products = serializedObject.FindProperty(\"products\");\n            _isValidatePurchase = serializedObject.FindProperty(\"isValidatePurchase\");\n            _isCustomValidatePurchase = serializedObject.FindProperty(\"isCustomValidatePurchase\");\n            _googlePlayStoreKey = serializedObject.FindProperty(\"googlePlayStoreKey\");\n        }\n\n        public override void OnInspectorGUI()\n        {\n            serializedObject.Update();\n            Initialize();\n            EditorGUILayout.PropertyField(_skusData);\n            EditorGUILayout.PropertyField(_products);\n            if (GUILayout.Button(\"Generate Product From SkusData\"))\n            {\n                GenerateProduct();\n            }\n\n            EditorGUILayout.PropertyField(_isValidatePurchase);\n            if (_isValidatePurchase.boolValue)\n            {\n                EditorGUILayout.PropertyField(_isCustomValidatePurchase);\n                EditorGUILayout.PropertyField(_googlePlayStoreKey);\n                if (GUILayout.Button(\"Obfuscator Key\"))\n                {\n                    ObfuscatorKey();\n                }\n            }\n\n            serializedObject.ApplyModifiedProperties();\n        }\n\n        void GenerateProduct()\n        {\n            _iapSetting.Products.Clear();\n            for (int i = 0; i < _iapSetting.SkusData.Count; i++)\n            {\n                bool isCustomName = false;\n                var data = _iapSetting.SkusData[i];\n                string itemName = data.Id.Split('.').Last();\n                if (!string.IsNullOrEmpty(data.customProductName))\n                {\n                    isCustomName = true;\n                    itemName = data.customProductName;\n                }\n\n                var itemDataVariable =\n                    CreateAsset.CreateAndGetScriptableAssetByName<IapDataVariable>(\"/Iap/Products\",\n                        isCustomName ? $\"{itemName.ToLower()}\" : $\"iap_{itemName.ToLower()}\");\n                itemDataVariable.androidId = data.androidId;\n                itemDataVariable.iosId = data.iosId;\n                itemDataVariable.productType = data.productType;\n                _iapSetting.Products.Add(itemDataVariable);\n            }\n\n            serializedObject.ApplyModifiedProperties();\n            EditorUtility.SetDirty(target);\n            AssetDatabase.SaveAssets();\n            AssetDatabase.Refresh();\n        }\n\n        void ObfuscatorKey()\n        {\n            var googleError = \"\";\n            var appleError = \"\";\n            ObfuscationGenerator.ObfuscateSecrets(includeGoogle: true,\n                appleError: ref googleError,\n                googleError: ref appleError,\n                googlePlayPublicKey: _iapSetting.GooglePlayStoreKey);\n            string pathAsmdef =\n                FileExtension.GetPathFileInCurrentEnvironment(\n                    $\"VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdef.txt\");\n            string pathAsmdefMeta =\n                FileExtension.GetPathFileInCurrentEnvironment(\n                    $\"VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdefMeta.txt\");\n            var asmdef = (TextAsset)AssetDatabase.LoadAssetAtPath(pathAsmdef, typeof(TextAsset));\n            var meta = (TextAsset)AssetDatabase.LoadAssetAtPath(pathAsmdefMeta, typeof(TextAsset));\n            string path = Path.Combine(TangleFileConsts.k_OutputPath, \"virtuesky.purchasing.generate.asmdef\");\n            string pathMeta = Path.Combine(TangleFileConsts.k_OutputPath, \"virtuesky.purchasing.generate.asmdef.meta\");\n            if (!File.Exists(path))\n            {\n                var writer = new StreamWriter(path, false);\n                writer.Write(asmdef.text);\n                writer.Close();\n            }\n\n            if (!File.Exists(pathMeta))\n            {\n                var writer = new StreamWriter(pathMeta, false);\n                writer.Write(meta.text);\n                writer.Close();\n            }\n\n            AssetDatabase.ImportAsset(path);\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Editor/IapSettingEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b423ca1e7e1e4e6ca2c02e2f47fe5551\ntimeCreated: 1700036744"
  },
  {
    "path": "VirtueSky/Iap/Editor/ObfuscationGenerator.cs",
    "content": "﻿#if UNITY_EDITOR\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Iap\n{\n    public class ObfuscationGenerator\n    {\n        private const string m_GeneratedCredentialsTemplateFilename = \"IAPGeneratedCredentials.cs.template\";\n        private const string m_GeneratedCredentialsTemplateFilenameNoExtension = \"IAPGeneratedCredentials.cs\";\n\n        private const string k_AppleCertPath = \"Packages/com.unity.purchasing/Editor/AppleIncRootCertificate.cer\";\n        private const string k_AppleStoreKitTestCertPath = \"Packages/com.unity.purchasing/Editor/StoreKitTestCertificate.cer\";\n\n        private const string k_AppleClassIncompleteErr = \"Invalid Apple Root Certificate\";\n        private const string k_AppleStoreKitTestClassIncompleteErr = \"Invalid Apple StoreKit Test Certificate\";\n\n        internal static string ObfuscateAppleSecrets()\n        {\n            var appleError = WriteObfuscatedAppleClassAsAsset();\n\n            AssetDatabase.Refresh();\n\n            return appleError;\n        }\n\n        internal static string ObfuscateGoogleSecrets(string googlePlayPublicKey)\n        {\n            var googleError = WriteObfuscatedGooglePlayClassAsAsset(googlePlayPublicKey);\n\n            AssetDatabase.Refresh();\n\n            return googleError;\n        }\n\n        /// <summary>\n        /// Generates specified obfuscated class files.\n        /// </summary>\n        internal static void ObfuscateSecrets(bool includeGoogle, ref string appleError, ref string googleError, string googlePlayPublicKey)\n        {\n            try\n            {\n                // First things first! Obfuscate! XHTLOA!\n                appleError = WriteObfuscatedAppleClassAsAsset();\n\n                if (includeGoogle)\n                {\n                    googleError = WriteObfuscatedGooglePlayClassAsAsset(googlePlayPublicKey);\n                }\n            }\n            catch (Exception e)\n            {\n                Debug.LogWarning(e.StackTrace);\n            }\n\n            // Ensure all the Tangle classes exist, even if they were not generated at this time.\n            if (!DoesGooglePlayTangleClassExist())\n            {\n                try\n                {\n                    WriteObfuscatedClassAsAsset(TangleFileConsts.k_GooglePlayClassPrefix,\n                        0,\n                        new int[0],\n                        new byte[0],\n                        false);\n                }\n                catch (Exception e)\n                {\n                    Debug.LogWarning(e.StackTrace);\n                }\n            }\n\n            AssetDatabase.Refresh();\n        }\n\n        private static string WriteObfuscatedAppleClassAsAsset()\n        {\n            var err = WriteObfuscatedAppleClassAsAsset(k_AppleCertPath, k_AppleClassIncompleteErr, TangleFileConsts.k_AppleClassPrefix);\n\n            if (err == null)\n            {\n                err = WriteObfuscatedAppleClassAsAsset(k_AppleStoreKitTestCertPath,\n                    k_AppleStoreKitTestClassIncompleteErr,\n                    TangleFileConsts.k_AppleStoreKitTestClassPrefix);\n            }\n\n            return err;\n        }\n\n        private static string WriteObfuscatedAppleClassAsAsset(string certPath, string classIncompleteErr, string classPrefix)\n        {\n            string appleError = null;\n            var key = 0;\n            var order = new int[0];\n            var tangled = new byte[0];\n            try\n            {\n                var bytes = File.ReadAllBytes(certPath);\n                order = new int[bytes.Length / 20 + 1];\n\n                // TODO: Integrate with upgraded Tangle!\n\n                tangled = TangleObfuscator.Obfuscate(bytes, order, out key);\n            }\n            catch (Exception e)\n            {\n                Debug.LogWarning($\"{classIncompleteErr}. Generating incomplete credentials file. \" + e);\n                appleError = $\"  {classIncompleteErr}\";\n            }\n\n            WriteObfuscatedClassAsAsset(classPrefix,\n                key,\n                order,\n                tangled,\n                tangled.Length != 0);\n\n            return appleError;\n        }\n\n        private static string WriteObfuscatedGooglePlayClassAsAsset(string googlePlayPublicKey)\n        {\n            string googleError = null;\n            var key = 0;\n            var order = new int[0];\n            var tangled = new byte[0];\n            try\n            {\n                var bytes = Convert.FromBase64String(googlePlayPublicKey);\n                order = new int[bytes.Length / 20 + 1];\n\n                tangled = TangleObfuscator.Obfuscate(bytes, order, out key);\n            }\n            catch (Exception e)\n            {\n                Debug.LogWarning(\"Invalid Google Play Public Key. Generating incomplete credentials file. \" + e);\n                googleError = \"  The Google Play License Key is invalid. GooglePlayTangle was generated with incomplete credentials.\";\n            }\n\n            WriteObfuscatedClassAsAsset(TangleFileConsts.k_GooglePlayClassPrefix,\n                key,\n                order,\n                tangled,\n                tangled.Length != 0);\n\n            return googleError;\n        }\n\n        private static string FullPathForTangleClass(string classnamePrefix)\n        {\n            return Path.Combine(TangleFileConsts.k_OutputPath, string.Format($\"{classnamePrefix}{TangleFileConsts.k_ObfuscationClassSuffix}\"));\n        }\n\n        internal static bool DoesAppleTangleClassExist()\n        {\n            return ObfuscatedClassExists(TangleFileConsts.k_AppleClassPrefix) && ObfuscatedClassExists(TangleFileConsts.k_AppleStoreKitTestClassPrefix);\n        }\n\n        internal static bool DoesGooglePlayTangleClassExist()\n        {\n            return ObfuscatedClassExists(TangleFileConsts.k_GooglePlayClassPrefix);\n        }\n\n        private static bool ObfuscatedClassExists(string classnamePrefix)\n        {\n            return File.Exists(FullPathForTangleClass(classnamePrefix));\n        }\n\n        private static void WriteObfuscatedClassAsAsset(string classnamePrefix, int key, int[] order, byte[] data, bool populated)\n        {\n            var substitutionDictionary = new Dictionary<string, string>()\n            {\n                { \"{NAME}\", classnamePrefix.ToString() },\n                { \"{KEY}\", key.ToString() },\n                { \"{ORDER}\", String.Format(\"{0}\", String.Join(\",\", Array.ConvertAll(order, i => i.ToString()))) },\n                { \"{DATA}\", Convert.ToBase64String(data) },\n                { \"{POPULATED}\", populated.ToString().ToLowerInvariant() } // Defaults to XML-friendly values\n            };\n\n            var templateText = LoadTemplateText(out var templateRelativePath);\n\n            if (templateText != null)\n            {\n                var outfileText = templateText;\n\n                // Apply the parameters to the template\n                foreach (var pair in substitutionDictionary)\n                {\n                    outfileText = outfileText.Replace(pair.Key, pair.Value);\n                }\n\n                Directory.CreateDirectory(TangleFileConsts.k_OutputPath);\n                File.WriteAllText(FullPathForTangleClass(classnamePrefix), outfileText);\n            }\n        }\n\n        /// <summary>\n        /// Loads the template file.\n        /// </summary>\n        /// <returns>The template file's text.</returns>\n        /// <param name=\"templateRelativePath\">Relative Assets/ path to template file.</param>\n        private static string LoadTemplateText(out string templateRelativePath)\n        {\n            var assetGUIDs = AssetDatabase.FindAssets(m_GeneratedCredentialsTemplateFilenameNoExtension);\n            string templateGUID = null;\n            templateRelativePath = null;\n\n            if (assetGUIDs.Length > 0)\n            {\n                templateGUID = assetGUIDs[0];\n            }\n            else\n            {\n                Debug.LogError(string.Format(\"Could not find template \\\"{0}\\\"\", m_GeneratedCredentialsTemplateFilename));\n            }\n\n            string templateText = null;\n\n            if (templateGUID != null)\n            {\n                templateRelativePath = AssetDatabase.GUIDToAssetPath(templateGUID);\n\n                var templateAbsolutePath = Path.GetDirectoryName(Application.dataPath) + Path.DirectorySeparatorChar + templateRelativePath;\n\n                templateText = File.ReadAllText(templateAbsolutePath);\n            }\n\n            return templateText;\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Editor/ObfuscationGenerator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ec3ca9e8aabd499eb4a3cba5aa6b34c4\ntimeCreated: 1697512782"
  },
  {
    "path": "VirtueSky/Iap/Editor/TangleFileConsts.cs",
    "content": "﻿#if UNITY_EDITOR\nnamespace VirtueSky.Iap\n{\n    public class TangleFileConsts\n    {\n        internal const string k_OutputPath = \"Assets/_Sunflower/Scripts/UnityPurchasing/generated\";\n\n        internal const string k_AppleClassPrefix = \"Apple\";\n        internal const string k_AppleStoreKitTestClassPrefix = \"AppleStoreKitTest\";\n        internal const string k_GooglePlayClassPrefix = \"GooglePlay\";\n        internal const string k_ObfuscationClassSuffix = \"Tangle.cs\";\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Editor/TangleFileConsts.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ab500741417a4e52a5809cb90bf12e56\ntimeCreated: 1697512817"
  },
  {
    "path": "VirtueSky/Iap/Editor/TangleObfuscator.cs",
    "content": "﻿#if UNITY_EDITOR\nusing System;\nusing System.Linq;\n\nnamespace VirtueSky.Iap\n{\n    public static class TangleObfuscator\n    {\n        /// <summary>\n        /// An Exception thrown when the tangle order array provided is invalid or shorter than the number of data slices made.\n        /// </summary>\n        public class InvalidOrderArray : Exception\n        {\n        }\n\n        /// <summary>\n        /// Generates the obfucscation tangle data.\n        /// </summary>\n        /// <param name=\"data\"> The Apple or GooglePlay public key data to be obfuscated. </param>\n        /// <param name=\"order\"> The array, passed by reference, of order of the data slices used to obfuscate the data with. </param>\n        /// <param name=\"rkey\"> Outputs the encryption key to deobfuscate the tangled data at runtime </param>\n        /// <returns>The obfucated public key</returns>\n        public static byte[] Obfuscate(byte[] data, int[] order, out int rkey)\n        {\n            var rnd = new System.Random();\n            var key = rnd.Next(2, 255);\n            var res = new byte[data.Length];\n            var slices = data.Length / 20 + 1;\n\n            if (order == null || order.Length < slices)\n            {\n                throw new InvalidOrderArray();\n            }\n\n            Array.Copy(data, res, data.Length);\n            for (var i = 0; i < slices - 1; i++)\n            {\n                var j = rnd.Next(i, slices - 1);\n                order[i] = j;\n                var sliceSize = 20; // prob should be configurable\n                var tmp = res.Skip(i * 20).Take(sliceSize).ToArray(); // tmp = res[i*20 .. slice]\n                Array.Copy(res,\n                    j * 20,\n                    res,\n                    i * 20,\n                    sliceSize); // res[i] = res[j*20 .. slice]\n                Array.Copy(tmp,\n                    0,\n                    res,\n                    j * 20,\n                    sliceSize); // res[j] = tmp\n            }\n\n            order[slices - 1] = slices - 1;\n\n            rkey = key;\n            return res.Select(x => (byte)(x ^ key)).ToArray();\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Editor/TangleObfuscator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 37539c07e6d2407bb3da42442654c120\ntimeCreated: 1697512870"
  },
  {
    "path": "VirtueSky/Iap/Editor/Virtusky.Sunflower.Iap.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtusky.Sunflower.Iap.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:0566ef25681cb4cec8714d50dda26ad1\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:60bfecf5cb232594891bc622f40d6bed\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:0b6289df6f84a6f4b982ff72d23e0273\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Iap/Editor/Virtusky.Sunflower.Iap.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 405e8b335a1c8114fb36942b7f97083f\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 90fc5ff7994c4925afac4c80fe45572f\ntimeCreated: 1697194680"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapDataVariable.cs",
    "content": "﻿#if VIRTUESKY_IAP\nusing System;\nusing System.Threading.Tasks;\nusing Cysharp.Threading.Tasks;\nusing UnityEngine;\nusing UnityEngine.Purchasing;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Iap\n{\n    [Serializable]\n    [EditorIcon(\"scriptable_iap\")]\n    public class IapDataVariable : ScriptableObject\n    {\n        [ReadOnly] public string androidId;\n        [ReadOnly] public string iosId;\n        [ReadOnly] public ProductType productType;\n\n        [Tooltip(\"Price config used for UI\"), Space]\n        public float priceConfig;\n\n        [SerializeField] private IapPurchaseSuccess onPurchaseSuccess;\n        [SerializeField] private IapPurchaseFailed onPurchaseFailed;\n        internal IapPurchaseSuccess OnPurchaseSuccess => onPurchaseSuccess;\n        internal IapPurchaseFailed OnPurchaseFailed => onPurchaseFailed;\n\n        [NonSerialized] public Action purchaseSuccessCallback;\n        [NonSerialized] public Action<string> purchaseFailedCallback;\n\n        private IapManager iapManager;\n        public string Id \n        {\n            get \n            {\n#if UNITY_ANDROID\n                return androidId;\n#elif UNITY_IOS\n                return iosId;\n#else\n                return string.Empty;\n#endif\n            }\n        }\n        internal void InitIapManager(IapManager _iapManager)\n        {\n            iapManager = _iapManager;\n        }\n\n        public Product GetProduct()\n        {\n            if (iapManager == null) return null;\n            return iapManager.GetProduct(this);\n        }\n\n        public SubscriptionInfo GetSubscriptionInfo()\n        {\n            if (iapManager == null) return null;\n            return iapManager.GetSubscriptionInfo(this);\n        }\n\n        public void Purchase()\n        {\n            if (iapManager == null) return;\n            iapManager.PurchaseProduct(this);\n        }\n\n        public bool IsPurchased()\n        {\n            if (iapManager == null) return false;\n            return iapManager.IsPurchasedProduct(this);\n        }\n\n        public string GetLocalizedPriceString()\n        {\n            if (GetProduct() == null) return String.Empty;\n            return GetProduct().metadata.localizedPriceString;\n        }\n\n        public string GetIsoCurrencyCode()\n        {\n            if (GetProduct() == null) return String.Empty;\n            return GetProduct().metadata.isoCurrencyCode;\n        }\n\n        public string GetLocalizedDescription()\n        {\n            if (GetProduct() == null) return String.Empty;\n            return GetProduct().metadata.localizedDescription;\n        }\n\n        public string GetLocalizedTitle()\n        {\n            if (GetProduct() == null) return String.Empty;\n            return GetProduct().metadata.localizedTitle;\n        }\n\n        public decimal GetLocalizedPrice()\n        {\n            if (GetProduct() == null) return 0;\n            return GetProduct().metadata.localizedPrice;\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapDataVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 40a793fde2834e079aa3418f036b9e09\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: a7c0b6e003e41ca408cabaf952160992, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapManager.cs",
    "content": "#if VIRTUESKY_IAP\nusing System;\nusing Cysharp.Threading.Tasks;\nusing UnityEngine;\nusing UnityEngine.Purchasing;\nusing UnityEngine.Purchasing.Extension;\nusing VirtueSky.Core;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\n\nnamespace VirtueSky.Iap\n{\n    [EditorIcon(\"icon_controller\"), HideMonoScript]\n    public class IapManager : BaseMono, IDetailedStoreListener\n    {\n        [Space] [SerializeField] private bool dontDestroyOnLoad = false;\n        [Tooltip(\"Require\"), SerializeField] private IapSetting iapSetting;\n\n        [Tooltip(\"Allows nulls\"), SerializeField]\n        private BooleanEvent changePreventDisplayAppOpenEvent;\n\n\n        private IStoreController _controller;\n        private IExtensionProvider _extensionProvider;\n        private static event Action RestoreEvent;\n        public static event Func<bool> CustomValidatePurchaseEvent;\n        public static bool IsInitialized { get; private set; }\n        public static void Restore() => RestoreEvent?.Invoke();\n\n        private void Awake()\n        {\n            if (dontDestroyOnLoad)\n            {\n                DontDestroyOnLoad(this.gameObject);\n            }\n        }\n\n        public override void OnEnable()\n        {\n            base.OnEnable();\n#if UNITY_IOS\n              RestoreEvent += RestorePurchase;\n#endif\n        }\n\n        public override void OnDisable()\n        {\n            base.OnDisable();\n#if UNITY_IOS\n             RestoreEvent -= RestorePurchase;\n#endif\n        }\n\n        private void Start()\n        {\n            Init();\n        }\n\n        private async void Init()\n        {\n            if (IsInitialized) return;\n            await UniTask.WaitUntil(() => UnityServiceInitialization.IsUnityServiceReady);\n            var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());\n            RequestProductData(builder);\n            builder.Configure<IGooglePlayConfiguration>();\n            UnityPurchasing.Initialize(this, builder);\n        }\n\n        #region Internal Api\n\n        internal bool IsPurchasedProduct(IapDataVariable product)\n        {\n            if (_controller == null) return false;\n            return product.productType is ProductType.NonConsumable or ProductType.Subscription &&\n                   _controller.products.WithID(product.Id).hasReceipt;\n        }\n\n        internal void PurchaseProduct(IapDataVariable product)\n        {\n            if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.Raise(true);\n            PurchaseProductInternal(product);\n        }\n\n        internal Product GetProduct(IapDataVariable product)\n        {\n            if (_controller == null) return null;\n            return _controller.products.WithID(product.Id);\n        }\n\n        internal SubscriptionInfo GetSubscriptionInfo(IapDataVariable product)\n        {\n            if (_controller == null || product.productType != ProductType.Subscription ||\n                !_controller.products.WithID(product.Id).hasReceipt) return null;\n            var subscriptionManager = new SubscriptionManager(GetProduct(product), null);\n            var subscriptionInfo = subscriptionManager.getSubscriptionInfo();\n            return subscriptionInfo;\n        }\n\n        #endregion\n\n        #region Implement\n\n        public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)\n        {\n            if (iapSetting.IsValidatePurchase)\n            {\n                if (iapSetting.IsCustomValidatePurchase)\n                {\n                    if ((bool)CustomValidatePurchaseEvent?.Invoke()) PurchaseVerified(purchaseEvent);\n                }\n                else\n                {\n                    bool validatedPurchase = true;\n#if (UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX) && !UNITY_EDITOR\n                    var validator =\n                        new UnityEngine.Purchasing.Security.CrossPlatformValidator(\n                            UnityEngine.Purchasing.Security.GooglePlayTangle.Data(),\n                            UnityEngine.Purchasing.Security.AppleTangle.Data(), Application.identifier);\n\n                    try\n                    {\n                        // On Google Play, result has a single product ID.\n                        // On Apple stores, receipts contain multiple products.\n                        var result = validator.Validate(purchaseEvent.purchasedProduct.receipt);\n                        Debug.Log(\"Receipt is valid\");\n                    }\n                    catch (UnityEngine.Purchasing.Security.IAPSecurityException)\n                    {\n                        Debug.Log(\"Invalid receipt, not unlocking content\");\n                        validatedPurchase = false;\n                    }\n\n#endif\n                    if (validatedPurchase) PurchaseVerified(purchaseEvent);\n                }\n            }\n            else\n            {\n                PurchaseVerified(purchaseEvent);\n            }\n\n            return PurchaseProcessingResult.Complete;\n        }\n\n        public void OnInitialized(IStoreController controller, IExtensionProvider extensions)\n        {\n            _controller = controller;\n            _extensionProvider = extensions;\n\n            foreach (var iapDataVariable in iapSetting.Products)\n            {\n                iapDataVariable.InitIapManager(this);\n            }\n\n            IsInitialized = true;\n        }\n\n        public void OnInitializeFailed(InitializationFailureReason error, string message)\n        {\n            OnInitializeFailed(error);\n        }\n\n        public void OnInitializeFailed(InitializationFailureReason error)\n        {\n            switch (error)\n            {\n                case InitializationFailureReason.AppNotKnown:\n                    Debug.LogError(\"Is your App correctly uploaded on the relevant publisher console?\");\n                    break;\n                case InitializationFailureReason.PurchasingUnavailable:\n                    Debug.LogWarning(\"In App Purchases disabled in device settings!\");\n                    break;\n                case InitializationFailureReason.NoProductsAvailable:\n                    Debug.LogWarning(\"No products available for purchase!\");\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(error), error, null);\n            }\n        }\n\n        public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)\n        {\n            InternalPurchaseFailed(product.definition.id, failureReason.ToString());\n        }\n\n        public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)\n        {\n            InternalPurchaseFailed(product.definition.id, failureDescription.reason.ToString());\n        }\n\n        #endregion\n\n        private IapDataVariable PurchaseProductInternal(IapDataVariable product)\n        {\n#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR\n            _controller?.InitiatePurchase(product.Id);\n#elif UNITY_EDITOR\n            InternalPurchaseSuccess(product.Id);\n#endif\n            return product;\n        }\n\n        void PurchaseVerified(PurchaseEventArgs purchaseEvent)\n        {\n            if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.Raise(false);\n            InternalPurchaseSuccess(purchaseEvent.purchasedProduct.definition.id);\n        }\n\n\n        #region Purchase Success\n\n        void InternalPurchaseSuccess(string id)\n        {\n            foreach (var product in iapSetting.Products)\n            {\n                if (product.Id != id) continue;\n                product.OnPurchaseSuccess.Raise();\n                Common.CallActionAndClean(ref product.purchaseSuccessCallback);\n            }\n        }\n\n        #endregion\n\n\n        #region Purchase Failed\n\n        private void InternalPurchaseFailed(string id, string reason)\n        {\n            if (changePreventDisplayAppOpenEvent != null) changePreventDisplayAppOpenEvent.Raise(false);\n            foreach (var product in iapSetting.Products)\n            {\n                if (product.Id != id) continue;\n                product.OnPurchaseFailed.Raise(reason);\n                Common.CallActionAndClean(ref product.purchaseFailedCallback, reason);\n            }\n        }\n\n        #endregion\n\n        private void RequestProductData(ConfigurationBuilder builder)\n        {\n            foreach (var p in iapSetting.Products)\n            {\n                builder.AddProduct(p.Id, p.productType);\n            }\n        }\n\n#if UNITY_IOS\n        internal void RestorePurchase()\n        {\n            if (!IsInitialized)\n            {\n                Debug.Log(\"Restore purchases fail. not initialized!\");\n                return;\n            }\n\n            if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.OSXPlayer)\n            {\n                Debug.Log(\"Restore purchase started ...\");\n\n                var storeProvider = _extensionProvider.GetExtension<IAppleExtensions>();\n                storeProvider.RestoreTransactions((b, s) =>\n                {\n                    // no purchase are avaiable to restore\n                    Debug.Log($\"Restore purchase continuing: {b}. If no further messages, no purchase available to restore.\");\n                });\n            }\n            else\n            {\n                Debug.Log(\"Restore purchase fail. not supported on this platform. current = \" + Application.platform);\n            }\n        }\n#endif\n#if UNITY_EDITOR\n        private void Reset()\n        {\n            iapSetting = CreateAsset.CreateAndGetScriptableAsset<VirtueSky.Iap.IapSetting>(\"/Iap/Setting\");\n        }\n#endif\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f80248d204b22674aa29ee9bc08e5df8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapPurchaseFailed.cs",
    "content": "﻿#if VIRTUESKY_IAP\nusing UnityEngine;\n\nnamespace VirtueSky.Iap\n{\n    public abstract class IapPurchaseFailed : ScriptableObject\n    {\n        public abstract void Raise(string reason);\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapPurchaseFailed.cs.meta",
    "content": "fileFormatVersion: 2\nguid: af820398821940e9937c417e16be949e\ntimeCreated: 1697447748"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapPurchaseSuccess.cs",
    "content": "﻿#if VIRTUESKY_IAP\nusing UnityEngine;\n\nnamespace VirtueSky.Iap\n{\n    public abstract class IapPurchaseSuccess : ScriptableObject\n    {\n        public abstract void Raise();\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapPurchaseSuccess.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 15b5e3eb49fb4a89a05254636725a8c3\ntimeCreated: 1697447681"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapSetting.cs",
    "content": "﻿#if VIRTUESKY_IAP\nusing System;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.Purchasing;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Iap\n{\n    [EditorIcon(\"icon_scriptable\")]\n    public class IapSetting : ScriptableObject\n    {\n        [SerializeField] private List<IapData> skusData = new List<IapData>();\n        [SerializeField] private List<IapDataVariable> products = new List<IapDataVariable>();\n\n        [Space, SerializeField] private bool isValidatePurchase;\n        [SerializeField] private bool isCustomValidatePurchase;\n#if UNITY_EDITOR\n        //[ShowIf(nameof(isValidatePurchase), true)] \n        [SerializeField, TextArea] private string googlePlayStoreKey;\n        public string GooglePlayStoreKey => googlePlayStoreKey;\n#endif\n        public List<IapData> SkusData => skusData;\n        public List<IapDataVariable> Products => products;\n        public bool IsValidatePurchase => isValidatePurchase;\n        public bool IsCustomValidatePurchase => isCustomValidatePurchase;\n    }\n\n    [Serializable]\n    public class IapData\n    {\n        public string androidId;\n        public string iosId;\n        public string customProductName;\n\n        public string Id \n        {\n            get \n            {\n#if UNITY_ANDROID\n                return androidId;\n#elif UNITY_IOS\n                return iosId;\n#else\n                return string.Empty;\n#endif\n            }\n        }\n        \n        public ProductType productType;\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapSetting.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8860d8e8b438431b873695abf0f12215\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapStatic.cs",
    "content": "﻿#if VIRTUESKY_IAP\nusing System;\nusing VirtueSky.Events;\n\nnamespace VirtueSky.Iap\n{\n    public static class IapStatic\n    {\n        public static IapDataVariable OnPurchaseCompleted(this IapDataVariable product, Action onComplete)\n        {\n            product.purchaseSuccessCallback = onComplete;\n            return product;\n        }\n\n        public static IapDataVariable OnPurchaseFailed(this IapDataVariable product, Action<string> onFailed)\n        {\n            product.purchaseFailedCallback = onFailed;\n            return product;\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Iap/Runtime/IapStatic.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ed5bcb6183b4ba082116c7095bc334e\ntimeCreated: 1697448017"
  },
  {
    "path": "VirtueSky/Iap/Runtime/Virtusky.Sunflower.Iap.asmdef",
    "content": "{\n    \"name\": \"Virtusky.Sunflower.Iap\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:60bfecf5cb232594891bc622f40d6bed\",\n        \"GUID:94e1de2458b07d0bf1e9f13e6ae06443\",\n        \"GUID:e63a64384cc3ef04cac761c1ce76e9c2\",\n        \"GUID:d0bf1e9f644394e1de13e6ae02458b07\",\n        \"GUID:08d1c582746949b40ba6a45cdb776bdf\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:a90b00dc83a89964cb7641c304492d29\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:f51ebe6a0ceec4240a699833d6309b23\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [\n        {\n            \"name\": \"com.unity.purchasing\",\n            \"expression\": \"4.11.0\",\n            \"define\": \"VIRTUESKY_IAP\"\n        }\n    ],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Iap/Runtime/Virtusky.Sunflower.Iap.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 0566ef25681cb4cec8714d50dda26ad1\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 6f2773e8e5742d14aa9914c2564e2aa2\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Iap.meta",
    "content": "fileFormatVersion: 2\nguid: 84a07bffd2183af498eeb05c1a93628f\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/.editorconfig",
    "content": "\n[*]\ncharset = utf-8\nend_of_line = crlf\ntrim_trailing_whitespace = false\ninsert_final_newline = false\nindent_style = space\nindent_size = 4\n\n# Microsoft .NET properties\ncsharp_indent_braces = false\ncsharp_indent_switch_labels = true\ncsharp_new_line_before_catch = true\ncsharp_new_line_before_else = true\ncsharp_new_line_before_finally = true\ncsharp_new_line_before_members_in_object_initializers = false\ncsharp_new_line_before_open_brace = all\ncsharp_new_line_between_query_expression_clauses = true\ncsharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion\ncsharp_preserve_single_line_blocks = true\ncsharp_space_after_cast = true\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\ncsharp_style_var_elsewhere = true:suggestion\ncsharp_style_var_for_built_in_types = true:suggestion\ncsharp_style_var_when_type_is_apparent = true:suggestion\ncsharp_using_directive_placement = outside_namespace:silent\ndotnet_naming_rule.constants_rule.severity = warning\ndotnet_naming_rule.constants_rule.style = upper_camel_case_style\ndotnet_naming_rule.constants_rule.symbols = constants_symbols\ndotnet_naming_rule.event_rule.severity = warning\ndotnet_naming_rule.event_rule.style = upper_camel_case_style\ndotnet_naming_rule.event_rule.symbols = event_symbols\ndotnet_naming_rule.interfaces_rule.severity = warning\ndotnet_naming_rule.interfaces_rule.style = i_upper_camel_case_style\ndotnet_naming_rule.interfaces_rule.symbols = interfaces_symbols\ndotnet_naming_rule.locals_rule.severity = warning\ndotnet_naming_rule.locals_rule.style = lower_camel_case_style\ndotnet_naming_rule.locals_rule.symbols = locals_symbols\ndotnet_naming_rule.local_constants_rule.severity = warning\ndotnet_naming_rule.local_constants_rule.style = lower_camel_case_style\ndotnet_naming_rule.local_constants_rule.symbols = local_constants_symbols\ndotnet_naming_rule.local_functions_rule.severity = warning\ndotnet_naming_rule.local_functions_rule.style = upper_camel_case_style\ndotnet_naming_rule.local_functions_rule.symbols = local_functions_symbols\ndotnet_naming_rule.method_rule.severity = warning\ndotnet_naming_rule.method_rule.style = upper_camel_case_style\ndotnet_naming_rule.method_rule.symbols = method_symbols\ndotnet_naming_rule.parameters_rule.severity = warning\ndotnet_naming_rule.parameters_rule.style = lower_camel_case_style\ndotnet_naming_rule.parameters_rule.symbols = parameters_symbols\ndotnet_naming_rule.private_constants_rule.severity = warning\ndotnet_naming_rule.private_constants_rule.style = upper_camel_case_style\ndotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols\ndotnet_naming_rule.private_instance_fields_rule.severity = warning\ndotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style_1\ndotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols\ndotnet_naming_rule.private_static_fields_rule.severity = warning\ndotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style_1\ndotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols\ndotnet_naming_rule.private_static_readonly_rule.severity = warning\ndotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style\ndotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols\ndotnet_naming_rule.property_rule.severity = warning\ndotnet_naming_rule.property_rule.style = upper_camel_case_style\ndotnet_naming_rule.property_rule.symbols = property_symbols\ndotnet_naming_rule.public_fields_rule.severity = warning\ndotnet_naming_rule.public_fields_rule.style = lower_camel_case_style\ndotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols\ndotnet_naming_rule.static_readonly_rule.severity = warning\ndotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style\ndotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols\ndotnet_naming_rule.types_and_namespaces_rule.severity = warning\ndotnet_naming_rule.types_and_namespaces_rule.style = upper_camel_case_style\ndotnet_naming_rule.types_and_namespaces_rule.symbols = types_and_namespaces_symbols\ndotnet_naming_rule.type_parameters_rule.severity = warning\ndotnet_naming_rule.type_parameters_rule.style = t_upper_camel_case_style\ndotnet_naming_rule.type_parameters_rule.symbols = type_parameters_symbols\ndotnet_naming_style.i_upper_camel_case_style.capitalization = pascal_case\ndotnet_naming_style.i_upper_camel_case_style.required_prefix = I\ndotnet_naming_style.lower_camel_case_style.capitalization = camel_case\ndotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case\ndotnet_naming_style.lower_camel_case_style_1.required_prefix = _\ndotnet_naming_style.t_upper_camel_case_style.capitalization = pascal_case\ndotnet_naming_style.t_upper_camel_case_style.required_prefix = T\ndotnet_naming_style.upper_camel_case_style.capitalization = pascal_case\ndotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected\ndotnet_naming_symbols.constants_symbols.applicable_kinds = field\ndotnet_naming_symbols.constants_symbols.required_modifiers = const\ndotnet_naming_symbols.event_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.event_symbols.applicable_kinds = event\ndotnet_naming_symbols.interfaces_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.interfaces_symbols.applicable_kinds = interface\ndotnet_naming_symbols.locals_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.locals_symbols.applicable_kinds = local\ndotnet_naming_symbols.local_constants_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.local_constants_symbols.applicable_kinds = local\ndotnet_naming_symbols.local_constants_symbols.required_modifiers = const\ndotnet_naming_symbols.local_functions_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.local_functions_symbols.applicable_kinds = local_function\ndotnet_naming_symbols.method_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.method_symbols.applicable_kinds = method\ndotnet_naming_symbols.parameters_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.parameters_symbols.applicable_kinds = parameter\ndotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_constants_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_constants_symbols.required_modifiers = const\ndotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static\ndotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private\ndotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field\ndotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly\ndotnet_naming_symbols.property_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.property_symbols.applicable_kinds = property\ndotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected\ndotnet_naming_symbols.public_fields_symbols.applicable_kinds = field\ndotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected\ndotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field\ndotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly\ndotnet_naming_symbols.types_and_namespaces_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,class,struct,enum,delegate\ndotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = *\ndotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter\ndotnet_separate_import_directive_groups = false\ndotnet_sort_system_directives_first = true\ndotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none\ndotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none\ndotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\ndotnet_style_predefined_type_for_member_access = true:suggestion\ndotnet_style_qualification_for_event = false:suggestion\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_method = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion\nfile_header_template = \n\n# ReSharper properties\nresharper_accessor_owner_body = expression_body\nresharper_alignment_tab_fill_style = use_spaces\nresharper_align_first_arg_by_paren = false\nresharper_align_linq_query = false\nresharper_align_multiline_array_and_object_initializer = false\nresharper_align_multiline_array_initializer = true\nresharper_align_multiline_ctor_init = true\nresharper_align_multiline_expression_braces = false\nresharper_align_multiline_implements_list = true\nresharper_align_multiline_property_pattern = false\nresharper_align_multiline_switch_expression = false\nresharper_align_multiline_type_argument = true\nresharper_align_multiline_type_parameter = true\nresharper_align_multline_type_parameter_constrains = false\nresharper_align_multline_type_parameter_list = false\nresharper_align_ternary = align_not_nested\nresharper_align_tuple_components = false\nresharper_allow_alias = true\nresharper_allow_comment_after_lbrace = false\nresharper_allow_far_alignment = false\nresharper_always_use_end_of_line_brace_style = false\nresharper_anonymous_method_declaration_braces = next_line\nresharper_apply_auto_detected_rules = true\nresharper_apply_on_completion = false\nresharper_arguments_anonymous_function = positional\nresharper_arguments_literal = positional\nresharper_arguments_named = positional\nresharper_arguments_other = positional\nresharper_arguments_skip_single = false\nresharper_arguments_string_literal = positional\nresharper_attribute_style = do_not_touch\nresharper_autodetect_indent_settings = true\nresharper_blank_lines_after_block_statements = 1\nresharper_blank_lines_after_case = 0\nresharper_blank_lines_after_control_transfer_statements = 0\nresharper_blank_lines_after_imports = 1\nresharper_blank_lines_after_multiline_statements = 0\nresharper_blank_lines_after_options = 1\nresharper_blank_lines_after_start_comment = 1\nresharper_blank_lines_after_using_list = 1\nresharper_blank_lines_around_accessor = 0\nresharper_blank_lines_around_auto_property = 1\nresharper_blank_lines_around_block_case_section = 0\nresharper_blank_lines_around_class_definition = 1\nresharper_blank_lines_around_field = 1\nresharper_blank_lines_around_function_declaration = 0\nresharper_blank_lines_around_function_definition = 1\nresharper_blank_lines_around_global_attribute = 0\nresharper_blank_lines_around_invocable = 1\nresharper_blank_lines_around_local_method = 1\nresharper_blank_lines_around_multiline_case_section = 0\nresharper_blank_lines_around_namespace = 1\nresharper_blank_lines_around_other_declaration = 0\nresharper_blank_lines_around_property = 1\nresharper_blank_lines_around_razor_functions = 1\nresharper_blank_lines_around_razor_helpers = 1\nresharper_blank_lines_around_razor_sections = 1\nresharper_blank_lines_around_region = 1\nresharper_blank_lines_around_single_line_accessor = 0\nresharper_blank_lines_around_single_line_auto_property = 0\nresharper_blank_lines_around_single_line_field = 0\nresharper_blank_lines_around_single_line_function_definition = 0\nresharper_blank_lines_around_single_line_invocable = 0\nresharper_blank_lines_around_single_line_local_method = 0\nresharper_blank_lines_around_single_line_property = 0\nresharper_blank_lines_around_single_line_type = 1\nresharper_blank_lines_around_type = 1\nresharper_blank_lines_before_block_statements = 0\nresharper_blank_lines_before_case = 0\nresharper_blank_lines_before_control_transfer_statements = 0\nresharper_blank_lines_before_multiline_statements = 0\nresharper_blank_lines_before_single_line_comment = 0\nresharper_blank_lines_inside_namespace = 0\nresharper_blank_lines_inside_region = 1\nresharper_blank_lines_inside_type = 0\nresharper_blank_line_after_pi = true\nresharper_braces_for_dowhile = required\nresharper_braces_for_fixed = required\nresharper_braces_for_for = required\nresharper_braces_for_foreach = required\nresharper_braces_for_ifelse = required\nresharper_braces_for_lock = required\nresharper_braces_for_using = required\nresharper_braces_for_while = required\nresharper_braces_redundant = false\nresharper_break_template_declaration = line_break\nresharper_can_use_global_alias = true\nresharper_constructor_or_destructor_body = block_body\nresharper_continuous_indent_multiplier = 1\nresharper_continuous_line_indent = single\nresharper_cpp_align_multiline_argument = true\nresharper_cpp_align_multiline_binary_expressions_chain = false\nresharper_cpp_align_multiline_calls_chain = true\nresharper_cpp_align_multiline_extends_list = true\nresharper_cpp_align_multiline_for_stmt = true\nresharper_cpp_align_multiline_parameter = true\nresharper_cpp_align_multiple_declaration = true\nresharper_cpp_case_block_braces = next_line_shifted_2\nresharper_cpp_indent_switch_labels = false\nresharper_cpp_max_line_length = 120\nresharper_cpp_new_line_before_while = true\nresharper_cpp_space_after_cast = false\nresharper_cpp_space_around_binary_operator = true\nresharper_cpp_wrap_lines = true\nresharper_csharp_align_multiline_argument = false\nresharper_csharp_align_multiline_binary_expressions_chain = true\nresharper_csharp_align_multiline_calls_chain = false\nresharper_csharp_align_multiline_expression = false\nresharper_csharp_align_multiline_extends_list = false\nresharper_csharp_align_multiline_for_stmt = false\nresharper_csharp_align_multiline_parameter = false\nresharper_csharp_align_multiple_declaration = false\nresharper_csharp_max_line_length = 120\nresharper_csharp_naming_rule.enum_member = AaBb\nresharper_csharp_naming_rule.method_property_event = AaBb\nresharper_csharp_naming_rule.other = AaBb\nresharper_csharp_naming_rule.public_fields = aaBb, AaBb\nresharper_csharp_new_line_before_while = false\nresharper_csharp_prefer_qualified_reference = false\nresharper_csharp_space_after_unary_operator = false\nresharper_csharp_wrap_lines = true\nresharper_cxxcli_property_declaration_braces = next_line\nresharper_default_exception_variable_name = e\nresharper_default_value_when_type_evident = default_literal\nresharper_default_value_when_type_not_evident = default_literal\nresharper_delete_quotes_from_solid_values = false\nresharper_disable_blank_line_changes = false\nresharper_disable_formatter = false\nresharper_disable_indenter = false\nresharper_disable_int_align = false\nresharper_disable_line_break_changes = false\nresharper_disable_line_break_removal = false\nresharper_disable_space_changes = false\nresharper_disable_space_changes_before_trailing_comment = false\nresharper_dont_remove_extra_blank_lines = false\nresharper_empty_block_style = multiline\nresharper_enable_wrapping = false\nresharper_enforce_line_ending_style = false\nresharper_event_handler_pattern_long = $object$On$event$\nresharper_event_handler_pattern_short = On$event$\nresharper_expression_braces = inside\nresharper_expression_pars = inside\nresharper_extra_spaces = remove_all\nresharper_force_attribute_style = separate\nresharper_force_chop_compound_do_expression = false\nresharper_force_chop_compound_if_expression = false\nresharper_force_chop_compound_while_expression = false\nresharper_format_leading_spaces_decl = false\nresharper_free_block_braces = next_line\nresharper_fsharp_align_function_signature_to_indentation = false\nresharper_fsharp_alternative_long_member_definitions = false\nresharper_fsharp_indent_on_try_with = false\nresharper_fsharp_keep_if_then_in_same_line = false\nresharper_fsharp_max_array_or_list_width = 40\nresharper_fsharp_max_elmish_width = 40\nresharper_fsharp_max_function_binding_width = 40\nresharper_fsharp_max_if_then_else_short_width = 40\nresharper_fsharp_max_infix_operator_expression = 50\nresharper_fsharp_max_line_length = 120\nresharper_fsharp_max_record_width = 40\nresharper_fsharp_max_value_binding_width = 40\nresharper_fsharp_multiline_block_brackets_on_same_column = false\nresharper_fsharp_newline_between_type_definition_and_members = false\nresharper_fsharp_semicolon_at_end_of_line = false\nresharper_fsharp_single_argument_web_mode = false\nresharper_fsharp_space_after_comma = true\nresharper_fsharp_space_after_semicolon = true\nresharper_fsharp_space_around_delimiter = true\nresharper_fsharp_space_before_class_constructor = false\nresharper_fsharp_space_before_colon = false\nresharper_fsharp_space_before_lowercase_invocation = true\nresharper_fsharp_space_before_member = false\nresharper_fsharp_space_before_parameter = true\nresharper_fsharp_space_before_semicolon = false\nresharper_fsharp_space_before_uppercase_invocation = false\nresharper_fsharp_wrap_lines = true\nresharper_function_declaration_return_type_style = do_not_change\nresharper_function_definition_return_type_style = do_not_change\nresharper_generator_mode = false\nresharper_html_attribute_indent = align_by_first_attribute\nresharper_html_linebreak_before_elements = body,div,p,form,h1,h2,h3\nresharper_html_max_blank_lines_between_tags = 2\nresharper_html_max_line_length = 120\nresharper_html_pi_attribute_style = on_single_line\nresharper_html_space_before_self_closing = false\nresharper_html_wrap_lines = true\nresharper_ignore_space_preservation = false\nresharper_include_prefix_comment_in_indent = false\nresharper_indent_access_specifiers_from_class = false\nresharper_indent_aligned_ternary = true\nresharper_indent_anonymous_method_block = false\nresharper_indent_case_from_select = true\nresharper_indent_child_elements = OneIndent\nresharper_indent_class_members_from_access_specifiers = false\nresharper_indent_comment = true\nresharper_indent_inside_namespace = true\nresharper_indent_invocation_pars = inside\nresharper_indent_method_decl_pars = inside\nresharper_indent_nested_fixed_stmt = false\nresharper_indent_nested_foreach_stmt = false\nresharper_indent_nested_for_stmt = false\nresharper_indent_nested_lock_stmt = false\nresharper_indent_nested_usings_stmt = false\nresharper_indent_nested_while_stmt = false\nresharper_indent_pars = inside\nresharper_indent_preprocessor_directives = normal\nresharper_indent_preprocessor_if = no_indent\nresharper_indent_preprocessor_other = no_indent\nresharper_indent_preprocessor_region = usual_indent\nresharper_indent_statement_pars = inside\nresharper_indent_text = OneIndent\nresharper_indent_typearg_angles = inside\nresharper_indent_typeparam_angles = inside\nresharper_indent_type_constraints = true\nresharper_indent_wrapped_function_names = false\nresharper_instance_members_qualify_declared_in = this_class, base_class\nresharper_int_align = false\nresharper_int_align_comments = false\nresharper_int_align_declaration_names = false\nresharper_int_align_eq = false\nresharper_int_align_fix_in_adjacent = true\nresharper_invocable_declaration_braces = next_line\nresharper_keep_blank_lines_in_code = 2\nresharper_keep_blank_lines_in_declarations = 2\nresharper_keep_existing_attribute_arrangement = true\nresharper_keep_existing_declaration_block_arrangement = false\nresharper_keep_existing_declaration_parens_arrangement = true\nresharper_keep_existing_embedded_arrangement = true\nresharper_keep_existing_embedded_block_arrangement = false\nresharper_keep_existing_enum_arrangement = false\nresharper_keep_existing_expr_member_arrangement = true\nresharper_keep_existing_invocation_parens_arrangement = true\nresharper_keep_existing_property_patterns_arrangement = true\nresharper_keep_existing_switch_expression_arrangement = true\nresharper_keep_nontrivial_alias = true\nresharper_keep_user_linebreaks = true\nresharper_keep_user_wrapping = true\nresharper_linebreaks_around_razor_statements = true\nresharper_linebreaks_inside_tags_for_elements_longer_than = 2147483647\nresharper_linebreaks_inside_tags_for_elements_with_child_elements = true\nresharper_linebreaks_inside_tags_for_multiline_elements = true\nresharper_linebreak_before_all_elements = false\nresharper_linebreak_before_multiline_elements = true\nresharper_linebreak_before_singleline_elements = false\nresharper_line_break_after_colon_in_member_initializer_lists = do_not_change\nresharper_line_break_after_comma_in_member_initializer_lists = false\nresharper_line_break_before_comma_in_member_initializer_lists = false\nresharper_linkage_specification_braces = end_of_line\nresharper_linkage_specification_indentation = none\nresharper_local_function_body = block_body\nresharper_max_array_initializer_elements_on_line = 10000\nresharper_max_attribute_length_for_same_line = 38\nresharper_max_enum_members_on_line = 3\nresharper_max_formal_parameters_on_line = 10000\nresharper_max_initializer_elements_on_line = 4\nresharper_max_invocation_arguments_on_line = 10000\nresharper_member_initializer_list_style = do_not_change\nresharper_method_or_operator_body = block_body\nresharper_namespace_declaration_braces = next_line\nresharper_namespace_indentation = all\nresharper_nested_ternary_style = autodetect\nresharper_never_outdent_pipe_operators = true\nresharper_new_line_before_catch = true\nresharper_new_line_before_else = true\nresharper_new_line_before_enumerators = true\nresharper_normalize_tag_names = false\nresharper_no_indent_inside_elements = html,body,thead,tbody,tfoot\nresharper_no_indent_inside_if_element_longer_than = 200\nresharper_object_creation_when_type_evident = target_typed\nresharper_object_creation_when_type_not_evident = explicitly_typed\nresharper_old_engine = false\nresharper_other_braces = next_line\nresharper_outdent_binary_operators = true\nresharper_outdent_binary_ops = false\nresharper_outdent_commas = false\nresharper_outdent_dots = false\nresharper_outdent_namespace_member = false\nresharper_outdent_ternary_ops = false\nresharper_parentheses_non_obvious_operations = none, bitwise, bitwise_inclusive_or, bitwise_exclusive_or, shift, bitwise_and\nresharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence\nresharper_pi_attributes_indent = align_by_first_attribute\nresharper_place_attribute_on_same_line = true\nresharper_place_comments_at_first_column = false\nresharper_place_constructor_initializer_on_same_line = true\nresharper_place_event_attribute_on_same_line = false\nresharper_place_expr_accessor_on_single_line = if_owner_is_single_line\nresharper_place_expr_method_on_single_line = if_owner_is_single_line\nresharper_place_expr_property_on_single_line = if_owner_is_single_line\nresharper_place_linq_into_on_new_line = true\nresharper_place_namespace_definitions_on_same_line = false\nresharper_place_property_attribute_on_same_line = false\nresharper_place_simple_case_statement_on_same_line = false\nresharper_place_simple_embedded_statement_on_same_line = if_owner_is_single_line\nresharper_place_simple_initializer_on_single_line = true\nresharper_place_simple_property_pattern_on_single_line = true\nresharper_place_simple_switch_expression_on_single_line = false\nresharper_place_type_constraints_on_same_line = true\nresharper_prefer_explicit_discard_declaration = false\nresharper_prefer_separate_deconstructed_variables_declaration = false\nresharper_preserve_spaces_inside_tags = pre,textarea\nresharper_qualified_using_at_nested_scope = false\nresharper_quote_style = doublequoted\nresharper_razor_prefer_qualified_reference = true\nresharper_remove_blank_lines_near_braces = false\nresharper_remove_blank_lines_near_braces_in_code = true\nresharper_remove_blank_lines_near_braces_in_declarations = true\nresharper_remove_this_qualifier = true\nresharper_requires_expression_braces = next_line\nresharper_resx_attribute_indent = single_indent\nresharper_resx_linebreak_before_elements = \nresharper_resx_max_blank_lines_between_tags = 0\nresharper_resx_max_line_length = 2147483647\nresharper_resx_pi_attribute_style = do_not_touch\nresharper_resx_space_before_self_closing = false\nresharper_resx_wrap_lines = false\nresharper_resx_wrap_tags_and_pi = false\nresharper_resx_wrap_text = false\nresharper_shaderlab_brace_style = next_line\nresharper_shaderlab_max_line_length = 120\nresharper_shaderlab_wrap_lines = true\nresharper_show_autodetect_configure_formatting_tip = true\nresharper_simple_block_style = do_not_change\nresharper_simple_case_statement_style = do_not_change\nresharper_simple_embedded_statement_style = do_not_change\nresharper_sort_attributes = false\nresharper_sort_class_selectors = false\nresharper_sort_usings = true\nresharper_sort_usings_lowercase_first = false\nresharper_spaces_around_eq_in_attribute = false\nresharper_spaces_around_eq_in_pi_attribute = false\nresharper_spaces_inside_tags = false\nresharper_space_after_attributes = true\nresharper_space_after_attribute_target_colon = true\nresharper_space_after_colon = true\nresharper_space_after_colon_in_case = true\nresharper_space_after_colon_in_inheritance_clause = true\nresharper_space_after_comma = true\nresharper_space_after_for_colon = true\nresharper_space_after_keywords_in_control_flow_statements = true\nresharper_space_after_last_attribute = false\nresharper_space_after_last_pi_attribute = false\nresharper_space_after_operator_keyword = true\nresharper_space_after_ptr_in_data_member = true\nresharper_space_after_ptr_in_data_members = false\nresharper_space_after_ptr_in_method = true\nresharper_space_after_ref_in_data_member = true\nresharper_space_after_ref_in_data_members = false\nresharper_space_after_ref_in_method = true\nresharper_space_after_semicolon_in_for_statement = true\nresharper_space_after_ternary_colon = true\nresharper_space_after_ternary_quest = true\nresharper_space_after_triple_slash = true\nresharper_space_after_type_parameter_constraint_colon = true\nresharper_space_around_additive_op = true\nresharper_space_around_alias_eq = true\nresharper_space_around_assignment_op = true\nresharper_space_around_assignment_operator = true\nresharper_space_around_deref_in_trailing_return_type = true\nresharper_space_around_lambda_arrow = true\nresharper_space_around_member_access_operator = false\nresharper_space_around_relational_op = true\nresharper_space_around_shift_op = true\nresharper_space_around_stmt_colon = true\nresharper_space_around_ternary_operator = true\nresharper_space_before_array_rank_parentheses = false\nresharper_space_before_attribute_target_colon = false\nresharper_space_before_checked_parentheses = false\nresharper_space_before_colon = false\nresharper_space_before_colon_in_case = false\nresharper_space_before_colon_in_inheritance_clause = true\nresharper_space_before_comma = false\nresharper_space_before_default_parentheses = false\nresharper_space_before_empty_invocation_parentheses = false\nresharper_space_before_empty_method_parentheses = false\nresharper_space_before_for_colon = true\nresharper_space_before_initializer_braces = false\nresharper_space_before_invocation_parentheses = false\nresharper_space_before_label_colon = false\nresharper_space_before_lambda_parentheses = false\nresharper_space_before_method_parentheses = false\nresharper_space_before_nameof_parentheses = false\nresharper_space_before_nullable_mark = false\nresharper_space_before_open_square_brackets = false\nresharper_space_before_pointer_asterik_declaration = false\nresharper_space_before_ptr_in_abstract_decl = false\nresharper_space_before_ptr_in_data_member = false\nresharper_space_before_ptr_in_data_members = true\nresharper_space_before_ptr_in_method = false\nresharper_space_before_ref_in_abstract_decl = false\nresharper_space_before_ref_in_data_member = false\nresharper_space_before_ref_in_data_members = true\nresharper_space_before_ref_in_method = false\nresharper_space_before_semicolon = false\nresharper_space_before_semicolon_in_for_statement = false\nresharper_space_before_singleline_accessorholder = true\nresharper_space_before_sizeof_parentheses = false\nresharper_space_before_template_args = false\nresharper_space_before_template_params = true\nresharper_space_before_ternary_colon = true\nresharper_space_before_ternary_quest = true\nresharper_space_before_trailing_comment = true\nresharper_space_before_typeof_parentheses = false\nresharper_space_before_type_argument_angle = false\nresharper_space_before_type_parameter_angle = false\nresharper_space_before_type_parameter_constraint_colon = true\nresharper_space_before_type_parameter_parentheses = true\nresharper_space_between_accessors_in_singleline_property = true\nresharper_space_between_attribute_sections = true\nresharper_space_between_closing_angle_brackets_in_template_args = false\nresharper_space_between_keyword_and_expression = true\nresharper_space_between_keyword_and_type = true\nresharper_space_between_method_call_empty_parameter_list_parentheses = false\nresharper_space_between_method_call_name_and_opening_parenthesis = false\nresharper_space_between_method_call_parameter_list_parentheses = false\nresharper_space_between_method_declaration_empty_parameter_list_parentheses = false\nresharper_space_between_method_declaration_name_and_open_parenthesis = false\nresharper_space_between_method_declaration_parameter_list_parentheses = false\nresharper_space_between_parentheses_of_control_flow_statements = false\nresharper_space_between_square_brackets = false\nresharper_space_between_typecast_parentheses = false\nresharper_space_in_singleline_accessorholder = true\nresharper_space_in_singleline_anonymous_method = true\nresharper_space_in_singleline_method = true\nresharper_space_near_postfix_and_prefix_op = false\nresharper_space_within_array_initialization_braces = false\nresharper_space_within_array_rank_empty_parentheses = false\nresharper_space_within_array_rank_parentheses = false\nresharper_space_within_attribute_angles = false\nresharper_space_within_checked_parentheses = false\nresharper_space_within_default_parentheses = false\nresharper_space_within_empty_braces = true\nresharper_space_within_empty_initializer_braces = false\nresharper_space_within_empty_invocation_parentheses = false\nresharper_space_within_empty_method_parentheses = false\nresharper_space_within_empty_template_params = false\nresharper_space_within_expression_parentheses = false\nresharper_space_within_initializer_braces = false\nresharper_space_within_invocation_parentheses = false\nresharper_space_within_method_parentheses = false\nresharper_space_within_nameof_parentheses = false\nresharper_space_within_parentheses = false\nresharper_space_within_single_line_array_initializer_braces = false\nresharper_space_within_sizeof_parentheses = false\nresharper_space_within_template_args = false\nresharper_space_within_template_params = false\nresharper_space_within_tuple_parentheses = false\nresharper_space_within_typeof_parentheses = false\nresharper_space_within_type_argument_angles = false\nresharper_space_within_type_parameter_angles = false\nresharper_space_within_type_parameter_parentheses = false\nresharper_special_else_if_treatment = true\nresharper_static_members_qualify_members = none\nresharper_static_members_qualify_with = declared_type\nresharper_stick_comment = true\nresharper_support_vs_event_naming_pattern = true\nresharper_toplevel_function_declaration_return_type_style = do_not_change\nresharper_toplevel_function_definition_return_type_style = do_not_change\nresharper_trailing_comma_in_multiline_lists = true\nresharper_trailing_comma_in_singleline_lists = true\nresharper_type_declaration_braces = next_line\nresharper_use_continuous_indent_inside_initializer_braces = true\nresharper_use_continuous_indent_inside_parens = true\nresharper_use_continuous_line_indent_in_expression_braces = false\nresharper_use_continuous_line_indent_in_method_pars = false\nresharper_use_heuristics_for_body_style = true\nresharper_use_indents_from_main_language_in_file = true\nresharper_use_indent_from_previous_element = true\nresharper_use_indent_from_vs = false\nresharper_use_roslyn_logic_for_evident_types = false\nresharper_vb_align_multiline_argument = true\nresharper_vb_align_multiline_expression = true\nresharper_vb_align_multiline_parameter = true\nresharper_vb_align_multiple_declaration = true\nresharper_vb_max_line_length = 120\nresharper_vb_place_field_attribute_on_same_line = true\nresharper_vb_place_method_attribute_on_same_line = false\nresharper_vb_place_type_attribute_on_same_line = false\nresharper_vb_prefer_qualified_reference = false\nresharper_vb_space_after_unary_operator = true\nresharper_vb_space_around_multiplicative_op = false\nresharper_vb_wrap_lines = true\nresharper_wrap_after_binary_opsign = true\nresharper_wrap_after_declaration_lpar = false\nresharper_wrap_after_dot = false\nresharper_wrap_after_dot_in_method_calls = false\nresharper_wrap_after_expression_lbrace = true\nresharper_wrap_after_invocation_lpar = false\nresharper_wrap_arguments_style = wrap_if_long\nresharper_wrap_around_elements = true\nresharper_wrap_array_initializer_style = wrap_if_long\nresharper_wrap_base_clause_style = wrap_if_long\nresharper_wrap_before_arrow_with_expressions = false\nresharper_wrap_before_binary_opsign = false\nresharper_wrap_before_colon = false\nresharper_wrap_before_comma = false\nresharper_wrap_before_comma_in_base_clause = false\nresharper_wrap_before_declaration_lpar = false\nresharper_wrap_before_declaration_rpar = false\nresharper_wrap_before_expression_rbrace = true\nresharper_wrap_before_extends_colon = false\nresharper_wrap_before_first_type_parameter_constraint = false\nresharper_wrap_before_invocation_lpar = false\nresharper_wrap_before_invocation_rpar = false\nresharper_wrap_before_linq_expression = false\nresharper_wrap_before_ternary_opsigns = true\nresharper_wrap_before_type_parameter_langle = false\nresharper_wrap_braced_init_list_style = wrap_if_long\nresharper_wrap_chained_binary_expressions = wrap_if_long\nresharper_wrap_chained_method_calls = wrap_if_long\nresharper_wrap_ctor_initializer_style = wrap_if_long\nresharper_wrap_enumeration_style = chop_if_long\nresharper_wrap_enum_declaration = chop_always\nresharper_wrap_extends_list_style = wrap_if_long\nresharper_wrap_for_stmt_header_style = chop_if_long\nresharper_wrap_multiple_declaration_style = chop_if_long\nresharper_wrap_multiple_type_parameter_constraints_style = chop_if_long\nresharper_wrap_object_and_collection_initializer_style = chop_if_long\nresharper_wrap_parameters_style = wrap_if_long\nresharper_wrap_property_pattern = chop_if_long\nresharper_wrap_switch_expression = chop_always\nresharper_wrap_ternary_expr_style = chop_if_long\nresharper_wrap_verbatim_interpolated_strings = no_wrap\nresharper_xmldoc_attribute_indent = single_indent\nresharper_xmldoc_linebreak_before_elements = summary,remarks,example,returns,param,typeparam,value,para\nresharper_xmldoc_max_blank_lines_between_tags = 0\nresharper_xmldoc_max_line_length = 120\nresharper_xmldoc_pi_attribute_style = do_not_touch\nresharper_xmldoc_space_before_self_closing = true\nresharper_xmldoc_wrap_lines = true\nresharper_xmldoc_wrap_tags_and_pi = true\nresharper_xmldoc_wrap_text = true\nresharper_xml_attribute_indent = align_by_first_attribute\nresharper_xml_linebreak_before_elements = \nresharper_xml_max_blank_lines_between_tags = 2\nresharper_xml_max_line_length = 120\nresharper_xml_pi_attribute_style = do_not_touch\nresharper_xml_space_before_self_closing = true\nresharper_xml_wrap_lines = true\nresharper_xml_wrap_tags_and_pi = true\nresharper_xml_wrap_text = false\n\n[*.asmdef]\nindent_style = space\nindent_size = 2\n\n[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,fs,fsi,fsscript,fsx,hlsl,hlsli,hlslinc,master,ml,mli,nuspec,paml,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}]\nindent_style = space\nindent_size = 4\ntab_width = 4\n"
  },
  {
    "path": "VirtueSky/Inspector/.github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\n<!-- A clear and concise description of what the bug is. -->\n\n**Expected behavior**\n<!-- A clear and concise description of what you expected to happen. -->\n\n**Code Sample**\n<!-- If applicable, add code sample to help explain your problem. -->\n```csharp\n// \n```\n\n**Screenshots**\n<!-- If applicable, add screenshots to help explain your problem. -->\n\n**Desktop:** <!-- e.g. Windows 10 -->\n**Unity version:** <!-- e.g. 2020.3.35f1 -->\n**Tri Inspector version:** <!-- e.g. 1.6.1 -->\n"
  },
  {
    "path": "VirtueSky/Inspector/.github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Feature request or Idea\n    url: https://github.com/codewriter-packages/Tri-Inspector/discussions/categories/ideas\n    about: Suggest an idea for this project.\n  - name: Question\n    url: https://github.com/codewriter-packages/Tri-Inspector/discussions/categories/q-a\n    about: Please ask and answer questions here.\n"
  },
  {
    "path": "VirtueSky/Inspector/.github/release.yml",
    "content": "# .github/release.yml\n\nchangelog:\n  categories:\n    - title: Breaking Changes\n      labels:\n        - breaking-change\n    - title: Features\n      labels:\n        - enhancement\n    - title: Fixes\n      labels:\n        - bug\n    - title: Changes\n      labels:\n        - \"*\"\n"
  },
  {
    "path": "VirtueSky/Inspector/.gitignore",
    "content": "*.*~\n*.db\n*.sln\n*.userprefs\n*.csproj\n*.pidb\n*.unityproj\n*.apk\n*.stackdump\n/Library\n/obj\n/Temp\n/Build*\n/Logs/\n/AssetBundles\n/Logs/\n.vs\n.vscode\n.idea\n.gradle\n*_LEGACY\n*.DotSettings.user\n/Assets/Plugins/Editor/JetBrains*\n/Assets/LEGACY*\n/Assets/TextMesh Pro*\n/Assets/Plugins/Sirenix*"
  },
  {
    "path": "VirtueSky/Inspector/Editor/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"TriInspector.Editor.Extras\")]\n[assembly: InternalsVisibleTo(\"TriInspector.Editor.Samples\")]\n[assembly: InternalsVisibleTo(\"TriInspector.Editor.Integrations.Odin\")]"
  },
  {
    "path": "VirtueSky/Inspector/Editor/AssemblyInfo.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 31eceb5f41944fc5a4afccb7697d3e61\ntimeCreated: 1652775741"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Attributes.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriValueDrawerAttribute : Attribute\n    {\n        public RegisterTriValueDrawerAttribute(Type drawerType, int order)\n        {\n            DrawerType = drawerType;\n            Order = order;\n        }\n\n        public Type DrawerType { get; }\n        public int Order { get; }\n        public bool ApplyOnArrayElement { get; set; } = true;\n    }\n\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriAttributeDrawerAttribute : Attribute\n    {\n        public RegisterTriAttributeDrawerAttribute(Type drawerType, int order)\n        {\n            DrawerType = drawerType;\n            Order = order;\n        }\n\n        public Type DrawerType { get; }\n        public int Order { get; }\n        public bool ApplyOnArrayElement { get; set; }\n    }\n\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriGroupDrawerAttribute : Attribute\n    {\n        public RegisterTriGroupDrawerAttribute(Type drawerType)\n        {\n            DrawerType = drawerType;\n        }\n\n        public Type DrawerType { get; }\n    }\n\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriPropertyHideProcessor : Attribute\n    {\n        public RegisterTriPropertyHideProcessor(Type processorType)\n        {\n            ProcessorType = processorType;\n        }\n\n        public Type ProcessorType { get; }\n        public bool ApplyOnArrayElement { get; set; }\n    }\n\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriPropertyDisableProcessor : Attribute\n    {\n        public RegisterTriPropertyDisableProcessor(Type processorType)\n        {\n            ProcessorType = processorType;\n        }\n\n        public Type ProcessorType { get; }\n        public bool ApplyOnArrayElement { get; set; }\n    }\n\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriValueValidatorAttribute : Attribute\n    {\n        public RegisterTriValueValidatorAttribute(Type validatorType)\n        {\n            ValidatorType = validatorType;\n        }\n\n        public Type ValidatorType { get; }\n        public bool ApplyOnArrayElement { get; set; } = true;\n    }\n\n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriAttributeValidatorAttribute : Attribute\n    {\n        public RegisterTriAttributeValidatorAttribute(Type validatorType)\n        {\n            ValidatorType = validatorType;\n        }\n\n        public Type ValidatorType { get; }\n        public bool ApplyOnArrayElement { get; set; }\n    }\n    \n    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]\n    public class RegisterTriTypeProcessorAttribute : Attribute\n    {\n        public RegisterTriTypeProcessorAttribute(Type processorType, int order)\n        {\n            ProcessorType = processorType;\n            Order = order;\n        }\n\n        public Type ProcessorType { get; }\n        public int Order { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Attributes.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 83289a1468a54453b62573925bc0635a\ntimeCreated: 1639581370"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EditorIconPostProcessor.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\n\nnamespace VirtueSky.Inspector\n{\n    /// <summary>\n    /// Postprocessor that processes all scripts using the EditorIcon attribute and assigns the matching icon guid (matching the icon query name) to the script's meta. It's a very simple solution (and very hacky), but works really great.\n    /// </summary>\n    public class EditorIconPostProcessor : AssetPostprocessor\n    {\n        /// <summary>\n        /// Called when new assets are imported, deleted or moved.\n        /// </summary>\n        /// <param name=\"importedAssets\">Imported assets.</param>\n        /// <param name=\"deletedAssets\">Deleted assets.</param>\n        /// <param name=\"movedAssets\">Moved assets.</param>\n        /// <param name=\"movedFromAssetPaths\">Moved from asset paths.</param>\n        static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets,\n            string[] movedFromAssetPaths)\n        {\n            var metaChangedForAssets = new List<string>();\n            foreach (string assetPath in importedAssets)\n            {\n                // NOTE: Below is not working since it's not compiled at this point\n                // We therefore need to do some string manipulations...\n                // var script = AssetDatabase.LoadAssetAtPath<MonoScript>(assetPath);\n                // var type = script?.GetClass();\n\n                var metaPath = $\"{assetPath}.meta\";\n                if (File.Exists(assetPath) && File.Exists(metaPath) && assetPath.EndsWith(\".cs\"))\n                {\n                    // Hack, hack, hack away....\n                    var scriptText = File.ReadAllText(assetPath);\n                    var containsEditorIconAttr = scriptText.Contains(\"[EditorIcon(\");\n\n                    if (containsEditorIconAttr)\n                    {\n                        // Extract icon name from attribute\n                        // We are assuming that template strings are not used\n                        var attrIconNameStartIndex = scriptText.IndexOf(\"[EditorIcon(\") + 13;\n                        var attrIconNameLength =\n                            scriptText.IndexOf(\"\\\")\", attrIconNameStartIndex) - attrIconNameStartIndex;\n                        var iconName = scriptText.Substring(attrIconNameStartIndex, attrIconNameLength);\n\n                        // Find guid based on icon name from attr\n                        var iconGuids = AssetDatabase.FindAssets($\"{iconName} t:texture2D\");\n                        var iconGuidsList = iconGuids.ToList();\n                        var guid = iconGuidsList.FirstOrDefault();\n\n                        if (!string.IsNullOrEmpty(guid))\n                        {\n                            // Read meta for script\n                            var scriptMetaTextLines = File.ReadAllLines(metaPath);\n                            var metaIconLine = $\"icon: {{fileID: 2800000, guid: {guid}, type: 3}}\";\n                            for (var i = 0; i < scriptMetaTextLines.Length; ++i)\n                            {\n                                var line = scriptMetaTextLines[i];\n                                // Find icon line\n                                if (line.Contains(\"icon: \") && !line.Contains(metaIconLine))\n                                {\n                                    var indexIconKeyName = line.IndexOf(\"icon: \");\n                                    var indexAfterClosingBrace = line.IndexOf(\"}\", indexIconKeyName) + 1;\n                                    var newLine =\n                                        line.Replace(\n                                            line.Substring(indexIconKeyName, indexAfterClosingBrace - indexIconKeyName),\n                                            metaIconLine);\n                                    scriptMetaTextLines[i] = newLine;\n                                    File.WriteAllLines(metaPath, scriptMetaTextLines);\n                                    metaChangedForAssets.Add(assetPath);\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            // We need to reimport all assets where the meta was changed\n            if (metaChangedForAssets.Count > 0)\n            {\n                foreach (var assetPath in metaChangedForAssets)\n                {\n                    AssetDatabase.ImportAsset(assetPath);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EditorIconPostProcessor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 01465eee3ed04ea2b30fe7e3ef9ae923\ntimeCreated: 1708661107"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/ExtendEnumDrawer.cs",
    "content": "﻿using UnityEngine;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nusing System.Reflection;\nusing System.Linq;\n\nnamespace VirtueSky.Inspector\n{\n    [CustomPropertyDrawer(typeof(ExtendEnumAttribute))]\n    public class ExtendEnumDrawer : PropertyDrawer\n    {\n        //Some static values to pass back and forth with the popup\n        static string newValueText = \"\";\n        static SerializedProperty currentProperty = null;\n        static bool showWindow = false;\n        static List<string> enumNames;\n        static int popupWidth = 150;\n        static int popupHeight = 90;\n\n        //Our class to make the popup\n        public class NewValuePopup : PopupWindowContent\n        {\n            public override void OnGUI(Rect position)\n            {\n                EditorGUILayout.LabelField(\"New Value\", EditorStyles.wordWrappedLabel);\n\n                newValueText = GUILayout.TextField(newValueText).Trim();\n\n                float exitSize = 18;\n                if (GUI.Button(new Rect(position.width - exitSize, 0, exitSize, exitSize), \"X\"))\n                {\n                    this.editorWindow.Close();\n                }\n\n                GUILayout.BeginHorizontal();\n                if (GUILayout.Button(\"Confirm\"))\n                {\n                    List<string> names = enumNames;\n                    for (int i = 0; i < names.Count; i++)\n                    {\n                        names[i] = names[i].ToLower();\n                    }\n\n                    if (!names.Contains(newValueText.ToLower()))\n                    {\n                        //This sends our enum to go get created. Be safe little enum.\n                        FindClassFile(GetEnumName(currentProperty), newValueText);\n                        this.editorWindow.Close();\n                    }\n                    else\n                    {\n                        newValueText = newValueText + \"_Copy\";\n                    }\n                }\n\n                if (GUILayout.Button(\"Cancel\"))\n                {\n                    this.editorWindow.Close();\n                }\n\n                GUILayout.EndHorizontal();\n                GUIStyle small = new GUIStyle(EditorStyles.wordWrappedLabel);\n                small.fontSize = 9;\n                EditorGUILayout.LabelField(\"(To add multiple, separate with commas)\", small);\n            }\n\n            public override void OnOpen()\n            {\n                showWindow = true;\n                newValueText = \"\";\n                base.OnOpen();\n            }\n\n            public override void OnClose()\n            {\n                showWindow = false;\n                base.OnClose();\n            }\n\n            public override Vector2 GetWindowSize()\n            {\n                return new Vector2(popupWidth, popupHeight);\n            }\n        }\n\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            currentProperty = property;\n            ExtendEnumAttribute source = (ExtendEnumAttribute)attribute;\n            System.Enum enumVal = GetBaseProperty<System.Enum>(property);\n\n            enumNames = (property.enumDisplayNames).OfType<string>().ToList();\n            if (source.display)\n            {\n                int[] enumValues = (int[])(System.Enum.GetValues(enumVal.GetType()));\n                for (int i = 0; i < enumNames.Count; i++)\n                {\n                    enumNames[i] += \" | \" + enumValues[i];\n                }\n            }\n\n            EditorGUI.BeginProperty(position, label, property);\n            if (!showWindow)\n            {\n                if (enumNames.Count != 0)\n                {\n                    enumNames.Add(\"Add New...\");\n                    int newValue = EditorGUI.Popup(position, property.displayName, property.intValue, enumNames.ToArray());\n\n                    if (newValue == enumNames.Count - 1)\n                    {\n                        NewValuePopup popup = new NewValuePopup();\n                        PopupWindow.Show(new Rect(Screen.width / 2 - popupWidth / 2, position.y - popupHeight / 2, 0, 0), popup);\n\n                        newValueText = \"\";\n                    }\n                    else\n                    {\n                        property.intValue = newValue;\n                    }\n                }\n                else\n                {\n                    EditorGUI.LabelField(position, \"Extendable Enums needs at least one value in your declared enum.\");\n                }\n            }\n            else\n            {\n                EditorGUI.LabelField(position, \"Waiting for new value input.\");\n            }\n\n            EditorGUI.EndProperty();\n        }\n\n        //I know this is pretty much the same as GetBaseProperty, I was lazy, bite me.\n        static string GetEnumName(SerializedProperty prop)\n        {\n            string[] separatedPaths = prop.propertyPath.Split('.');\n            System.Object reflectionTarget = prop.serializedObject.targetObject as object;\n\n            foreach (var path in separatedPaths)\n            {\n                FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                string name = fieldInfo.FieldType.Name;\n                return name;\n            }\n\n            return \"Null\";\n        }\n\n        static T GetBaseProperty<T>(SerializedProperty prop)\n        {\n            string[] separatedPaths = prop.propertyPath.Split('.');\n            System.Object reflectionTarget = prop.serializedObject.targetObject as object;\n\n            foreach (var path in separatedPaths)\n            {\n                FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n                reflectionTarget = fieldInfo.GetValue(reflectionTarget);\n            }\n\n            return (T)reflectionTarget;\n        }\n\n        static void FindClassFile(string enumName, string newEnum)\n        {\n            KeyValuePair<string, string> codeFile = FindAllScriptFiles(Application.dataPath, \"enum \" + enumName);\n            if (codeFile.Key != \"NOPE\")\n                AddNewEnum(codeFile.Key, codeFile.Value, enumName, newEnum);\n            else\n                Debug.LogError(\"Could not find enum class\");\n        }\n\n        //Formatting is a little weird on this depending. It works pretty well with a single line enum format, but other than that it can do weird shit.\n        //But it still works, so it's fine... for now.\n        static void AddNewEnum(string classFile, string path, string enumName, string newEnum)\n        {\n            string[] originalSplit = classFile.Split(new[] { \"enum \" + enumName }, System.StringSplitOptions.RemoveEmptyEntries);\n            string newHalf = originalSplit[1];\n            string enumSection = newHalf.Split('}')[0];\n            string[] commas = enumSection.Split(',');\n            if (commas.Length == 0 && enumSection.Split('{')[0].Trim().Length == 0) //They've left the enum empty... for some reason.\n            {\n                Debug.Log(\"Uhh idk yet\");\n                newHalf = newHalf.Replace(enumSection, enumSection + newEnum);\n            }\n            else\n            {\n                bool commaAfter = commas[commas.Length - 1].Trim().Length == 0; //This should check if the weirdo added a comma after their last enum value.\n\n                if (commaAfter)\n                {\n                    newHalf = newHalf.Replace(enumSection, enumSection + newEnum + \", \");\n                }\n                else\n                {\n                    while (enumSection.Length > 0 && enumSection[enumSection.Length - 1] == ' ')\n                        enumSection = enumSection.Substring(0, enumSection.Length - 1);\n                    newHalf = newHalf.Replace(enumSection, enumSection + \", \" + newEnum);\n                }\n            }\n\n            string result = classFile.Replace(originalSplit[1], newHalf);\n            using (var file = File.Open(path, FileMode.Create))\n            {\n                using (var writer = new StreamWriter(file))\n                {\n                    writer.Write(result);\n                }\n            }\n\n            AssetDatabase.Refresh();\n        }\n\n        static KeyValuePair<string, string> FindAllScriptFiles(string startDir, string enumToFind)\n        {\n            try\n            {\n                foreach (string file in Directory.GetFiles(startDir))\n                {\n                    if ((file.Contains(\".cs\") || file.Contains(\".js\")) && !file.Contains(\".meta\"))\n                    {\n                        string current = File.ReadAllText(file);\n                        string currentTrimmed = current.Replace(\" \", \"\").Replace(\"\\n\", \"\").Replace(\"\\t\", \"\").Replace(\"\\r\", \"\");\n                        if (currentTrimmed.Contains(enumToFind.Replace(\" \", \"\") + \"{\"))\n                            return new KeyValuePair<string, string>(current, file);\n                    }\n                }\n\n                foreach (string dir in Directory.GetDirectories(startDir))\n                {\n                    KeyValuePair<string, string> result = FindAllScriptFiles(dir, enumToFind);\n                    if (result.Key != \"NOPE\")\n                        return result;\n                }\n            }\n            catch (System.Exception ex)\n            {\n                Debug.Log(ex.Message);\n            }\n\n            return new KeyValuePair<string, string>(\"NOPE\", \"NOPE\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/ExtendEnumDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b07c545637af41f47a101b6cf470e89f\ntimeCreated: 1521073357\nlicenseType: Store\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchableEnumDrawer.cs",
    "content": "﻿using System;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    /// <summary>\n    /// Draws the custom enum selector popup for enum fileds using the\n    /// SearchableEnumAttribute.\n    /// </summary>\n    [CustomPropertyDrawer(typeof(SearchableEnumAttribute))]\n    public class SearchableEnumDrawer : PropertyDrawer\n    {\n        private const string TYPE_ERROR =\n            \"SearchableEnum can only be used on enum fields.\";\n\n        /// <summary>\n        /// Cache of the hash to use to resolve the ID for the drawer.\n        /// </summary>\n        private int idHash;\n\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            // If this is not used on an eunum, show an error\n            if (property.type != \"Enum\")\n            {\n                GUIStyle errorStyle = \"CN EntryErrorIconSmall\";\n                Rect r = new Rect(position);\n                r.width = errorStyle.fixedWidth;\n                position.xMin = r.xMax;\n                GUI.Label(r, \"\", errorStyle);\n                GUI.Label(position, TYPE_ERROR);\n                return;\n            }\n\n            // By manually creating the control ID, we can keep the ID for the\n            // label and button the same. This lets them be selected together\n            // with the keyboard in the inspector, much like a normal popup.\n            if (idHash == 0) idHash = \"SearchableEnumDrawer\".GetHashCode();\n            int id = GUIUtility.GetControlID(idHash, FocusType.Keyboard, position);\n\n            label = EditorGUI.BeginProperty(position, label, property);\n            position = EditorGUI.PrefixLabel(position, id, label);\n\n            GUIContent buttonText;\n            // If the enum has changed, a blank entry\n            if (property.enumValueIndex < 0 || property.enumValueIndex >= property.enumDisplayNames.Length)\n            {\n                buttonText = new GUIContent();\n            }\n            else\n            {\n                buttonText = new GUIContent(property.enumDisplayNames[property.enumValueIndex]);\n            }\n\n            if (DropdownButton(id, position, buttonText))\n            {\n                Action<int> onSelect = i =>\n                {\n                    property.enumValueIndex = i;\n                    property.serializedObject.ApplyModifiedProperties();\n                };\n\n                SearchablePopup.Show(position, property.enumDisplayNames,\n                    property.enumValueIndex, onSelect);\n            }\n\n            EditorGUI.EndProperty();\n        }\n\n        /// <summary>\n        /// A custom button drawer that allows for a controlID so that we can\n        /// sync the button ID and the label ID to allow for keyboard\n        /// navigation like the built-in enum drawers.\n        /// </summary>\n        private static bool DropdownButton(int id, Rect position, GUIContent content)\n        {\n            Event current = Event.current;\n            switch (current.type)\n            {\n                case EventType.MouseDown:\n                    if (position.Contains(current.mousePosition) && current.button == 0)\n                    {\n                        Event.current.Use();\n                        return true;\n                    }\n\n                    break;\n                case EventType.KeyDown:\n                    if (GUIUtility.keyboardControl == id && current.character == '\\n')\n                    {\n                        Event.current.Use();\n                        return true;\n                    }\n\n                    break;\n                case EventType.Repaint:\n                    EditorStyles.popup.Draw(position, content, id, false);\n                    break;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchableEnumDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a8aa6bf08885446d813b3de2ed167fd6\ntimeCreated: 1700212255"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchablePopup.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    /// <summary>\n    /// A popup window that displays a list of options and may use a search\n    /// string to filter the displayed content. \n    /// </summary>\n    public class SearchablePopup : PopupWindowContent\n    {\n        #region -- Constants --------------------------------------------------\n\n        /// <summary> Height of each element in the popup list. </summary>\n        private const float ROW_HEIGHT = 16.0f;\n\n        /// <summary> How far to indent list entries. </summary>\n        private const float ROW_INDENT = 8.0f;\n\n        /// <summary> Name to use for the text field for search. </summary>\n        private const string SEARCH_CONTROL_NAME = \"EnumSearchText\";\n\n        #endregion -- Constants -----------------------------------------------\n\n        #region -- Static Functions -------------------------------------------\n\n        /// <summary> Show a new SearchablePopup. </summary>\n        /// <param name=\"activatorRect\">\n        /// Rectangle of the button that triggered the popup.\n        /// </param>\n        /// <param name=\"options\">List of strings to choose from.</param>\n        /// <param name=\"current\">\n        /// Index of the currently selected string.\n        /// </param>\n        /// <param name=\"onSelectionMade\">\n        /// Callback to trigger when a choice is made.\n        /// </param>\n        public static void Show(Rect activatorRect, string[] options, int current, Action<int> onSelectionMade)\n        {\n            SearchablePopup win =\n                new SearchablePopup(options, current, onSelectionMade);\n            PopupWindow.Show(activatorRect, win);\n        }\n\n        /// <summary>\n        /// Force the focused window to redraw. This can be used to make the\n        /// popup more responsive to mouse movement.\n        /// </summary>\n        private static void Repaint()\n        {\n            EditorWindow.focusedWindow.Repaint();\n        }\n\n        /// <summary> Draw a generic box. </summary>\n        /// <param name=\"rect\">Where to draw.</param>\n        /// <param name=\"tint\">Color to tint the box.</param>\n        private static void DrawBox(Rect rect, Color tint)\n        {\n            Color c = GUI.color;\n            GUI.color = tint;\n            GUI.Box(rect, \"\", Selection);\n            GUI.color = c;\n        }\n\n        #endregion -- Static Functions ----------------------------------------\n\n        #region -- Helper Classes ---------------------------------------------\n\n        /// <summary>\n        /// Stores a list of strings and can return a subset of that list that\n        /// matches a given filter string.\n        /// </summary>\n        private class FilteredList\n        {\n            /// <summary>\n            /// An entry in the filtererd list, mapping the text to the\n            /// original index.\n            /// </summary>\n            public struct Entry\n            {\n                public int Index;\n                public string Text;\n            }\n\n            /// <summary> All posibile items in the list. </summary>\n            private readonly string[] allItems;\n\n            /// <summary> Create a new filtered list. </summary>\n            /// <param name=\"items\">All The items to filter.</param>\n            public FilteredList(string[] items)\n            {\n                allItems = items;\n                Entries = new List<Entry>();\n                UpdateFilter(\"\");\n            }\n\n            /// <summary> The current string filtering the list. </summary>\n            public string Filter { get; private set; }\n\n            /// <summary> All valid entries for the current filter. </summary>\n            public List<Entry> Entries { get; private set; }\n\n            /// <summary> Total possible entries in the list. </summary>\n            public int MaxLength\n            {\n                get { return allItems.Length; }\n            }\n\n            /// <summary>\n            /// Sets a new filter string and updates the Entries that match the\n            /// new filter if it has changed.\n            /// </summary>\n            /// <param name=\"filter\">String to use to filter the list.</param>\n            /// <returns>\n            /// True if the filter is updated, false if newFilter is the same\n            /// as the current Filter and no update is necessary.\n            /// </returns>\n            public bool UpdateFilter(string filter)\n            {\n                if (Filter == filter)\n                    return false;\n\n                Filter = filter;\n                Entries.Clear();\n\n                for (int i = 0; i < allItems.Length; i++)\n                {\n                    if (string.IsNullOrEmpty(Filter) || allItems[i].ToLower().Contains(Filter.ToLower()))\n                    {\n                        Entry entry = new Entry\n                        {\n                            Index = i,\n                            Text = allItems[i]\n                        };\n                        if (string.Equals(allItems[i], Filter, StringComparison.CurrentCultureIgnoreCase))\n                            Entries.Insert(0, entry);\n                        else\n                            Entries.Add(entry);\n                    }\n                }\n\n                return true;\n            }\n        }\n\n        #endregion -- Helper Classes ------------------------------------------\n\n        #region -- Private Variables ------------------------------------------\n\n        /// <summary> Callback to trigger when an item is selected. </summary>\n        private readonly Action<int> onSelectionMade;\n\n        /// <summary>\n        /// Index of the item that was selected when the list was opened.\n        /// </summary>\n        private readonly int currentIndex;\n\n        /// <summary>\n        /// Container for all available options that does the actual string\n        /// filtering of the content.  \n        /// </summary>\n        private readonly FilteredList list;\n\n        /// <summary> Scroll offset for the vertical scroll area. </summary>\n        private Vector2 scroll;\n\n        /// <summary>\n        /// Index of the item under the mouse or selected with the keyboard.\n        /// </summary>\n        private int hoverIndex;\n\n        /// <summary>\n        /// An item index to scroll to on the next draw.\n        /// </summary>\n        private int scrollToIndex;\n\n        /// <summary>\n        /// An offset to apply after scrolling to scrollToIndex. This can be\n        /// used to control if the selection appears at the top, bottom, or\n        /// center of the popup.\n        /// </summary>\n        private float scrollOffset;\n\n        #endregion -- Private Variables ---------------------------------------\n\n        #region -- GUI Styles -------------------------------------------------\n\n        // GUIStyles implicitly cast from a string. This triggers a lookup into\n        // the current skin which will be the editor skin and lets us get some\n        // built-in styles.\n\n        private static GUIStyle SearchBox = \"ToolbarSeachTextField\";\n        private static GUIStyle CancelButton = \"ToolbarSeachCancelButton\";\n        private static GUIStyle DisabledCancelButton = \"ToolbarSeachCancelButtonEmpty\";\n        private static GUIStyle Selection = \"SelectionRect\";\n\n        #endregion -- GUI Styles ----------------------------------------------\n\n        #region -- Initialization ---------------------------------------------\n\n        private SearchablePopup(string[] names, int currentIndex, Action<int> onSelectionMade)\n        {\n            list = new FilteredList(names);\n            this.currentIndex = currentIndex;\n            this.onSelectionMade = onSelectionMade;\n\n            hoverIndex = currentIndex;\n            scrollToIndex = currentIndex;\n            scrollOffset = GetWindowSize().y - ROW_HEIGHT * 2;\n        }\n\n        #endregion -- Initialization ------------------------------------------\n\n        #region -- PopupWindowContent Overrides -------------------------------\n\n        public override void OnOpen()\n        {\n            base.OnOpen();\n            // Force a repaint every frame to be responsive to mouse hover.\n            EditorApplication.update += Repaint;\n        }\n\n        public override void OnClose()\n        {\n            base.OnClose();\n            EditorApplication.update -= Repaint;\n        }\n\n        public override Vector2 GetWindowSize()\n        {\n            return new Vector2(base.GetWindowSize().x,\n                Mathf.Min(600, list.MaxLength * ROW_HEIGHT +\n                               EditorStyles.toolbar.fixedHeight));\n        }\n\n        public override void OnGUI(Rect rect)\n        {\n            Rect searchRect = new Rect(0, 0, rect.width, EditorStyles.toolbar.fixedHeight);\n            Rect scrollRect = Rect.MinMaxRect(0, searchRect.yMax, rect.xMax, rect.yMax);\n\n            HandleKeyboard();\n            DrawSearch(searchRect);\n            DrawSelectionArea(scrollRect);\n        }\n\n        #endregion -- PopupWindowContent Overrides ----------------------------\n\n        #region -- GUI --------------------------------------------------------\n\n        private void DrawSearch(Rect rect)\n        {\n            if (Event.current.type == EventType.Repaint)\n                EditorStyles.toolbar.Draw(rect, false, false, false, false);\n\n            Rect searchRect = new Rect(rect);\n            searchRect.xMin += 6;\n            searchRect.xMax -= 6;\n            searchRect.y += 2;\n            searchRect.width -= CancelButton.fixedWidth;\n\n            GUI.FocusControl(SEARCH_CONTROL_NAME);\n            GUI.SetNextControlName(SEARCH_CONTROL_NAME);\n            string newText = GUI.TextField(searchRect, list.Filter, SearchBox);\n\n            if (list.UpdateFilter(newText))\n            {\n                hoverIndex = 0;\n                scroll = Vector2.zero;\n            }\n\n            searchRect.x = searchRect.xMax;\n            searchRect.width = CancelButton.fixedWidth;\n\n            if (string.IsNullOrEmpty(list.Filter))\n                GUI.Box(searchRect, GUIContent.none, DisabledCancelButton);\n            else if (GUI.Button(searchRect, \"x\", CancelButton))\n            {\n                list.UpdateFilter(\"\");\n                scroll = Vector2.zero;\n            }\n        }\n\n        private void DrawSelectionArea(Rect scrollRect)\n        {\n            Rect contentRect = new Rect(0, 0,\n                scrollRect.width - GUI.skin.verticalScrollbar.fixedWidth,\n                list.Entries.Count * ROW_HEIGHT);\n\n            scroll = GUI.BeginScrollView(scrollRect, scroll, contentRect);\n\n            Rect rowRect = new Rect(0, 0, scrollRect.width, ROW_HEIGHT);\n\n            for (int i = 0; i < list.Entries.Count; i++)\n            {\n                if (scrollToIndex == i &&\n                    (Event.current.type == EventType.Repaint\n                     || Event.current.type == EventType.Layout))\n                {\n                    Rect r = new Rect(rowRect);\n                    r.y += scrollOffset;\n                    GUI.ScrollTo(r);\n                    scrollToIndex = -1;\n                    scroll.x = 0;\n                }\n\n                if (rowRect.Contains(Event.current.mousePosition))\n                {\n                    if (Event.current.type == EventType.MouseMove ||\n                        Event.current.type == EventType.ScrollWheel)\n                        hoverIndex = i;\n                    if (Event.current.type == EventType.MouseDown)\n                    {\n                        onSelectionMade(list.Entries[i].Index);\n                        EditorWindow.focusedWindow.Close();\n                    }\n                }\n\n                DrawRow(rowRect, i);\n\n                rowRect.y = rowRect.yMax;\n            }\n\n            GUI.EndScrollView();\n        }\n\n        private void DrawRow(Rect rowRect, int i)\n        {\n            if (list.Entries[i].Index == currentIndex)\n                DrawBox(rowRect, Color.cyan);\n            else if (i == hoverIndex)\n                DrawBox(rowRect, Color.white);\n\n            Rect labelRect = new Rect(rowRect);\n            labelRect.xMin += ROW_INDENT;\n\n            GUI.Label(labelRect, list.Entries[i].Text);\n        }\n\n        /// <summary>\n        /// Process keyboard input to navigate the choices or make a selection.\n        /// </summary>\n        private void HandleKeyboard()\n        {\n            if (Event.current.type == EventType.KeyDown)\n            {\n                if (Event.current.keyCode == KeyCode.DownArrow)\n                {\n                    hoverIndex = Mathf.Min(list.Entries.Count - 1, hoverIndex + 1);\n                    Event.current.Use();\n                    scrollToIndex = hoverIndex;\n                    scrollOffset = ROW_HEIGHT;\n                }\n\n                if (Event.current.keyCode == KeyCode.UpArrow)\n                {\n                    hoverIndex = Mathf.Max(0, hoverIndex - 1);\n                    Event.current.Use();\n                    scrollToIndex = hoverIndex;\n                    scrollOffset = -ROW_HEIGHT;\n                }\n\n                if (Event.current.keyCode == KeyCode.Return)\n                {\n                    if (hoverIndex >= 0 && hoverIndex < list.Entries.Count)\n                    {\n                        onSelectionMade(list.Entries[hoverIndex].Index);\n                        EditorWindow.focusedWindow.Close();\n                    }\n                }\n\n                if (Event.current.keyCode == KeyCode.Escape)\n                {\n                    EditorWindow.focusedWindow.Close();\n                }\n            }\n        }\n\n        #endregion -- GUI -----------------------------------------------------\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue/SearchablePopup.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c47838d170794dbfa710dc4df2fe039e\ntimeCreated: 1700212328"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/EnumAttribue.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 7b63b2018c2b4135a61979cfe3964c52\ntimeCreated: 1700212559"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/HeaderLineDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    [CustomPropertyDrawer(typeof(HeaderLineAttribute))]\n    public class HeaderLineDrawer : DecoratorDrawer\n    {\n        private HeaderLineAttribute Target => attribute as HeaderLineAttribute;\n        private GUIStyle m_style = new GUIStyle(EditorStyles.boldLabel);\n        protected float singleLine = EditorGUIUtility.singleLineHeight;\n\n        public override void OnGUI(Rect _rect)\n        {\n            //Draw label\n            if (!string.IsNullOrWhiteSpace(Target.text))\n            {\n                EditorGUI.LabelField(_rect, Target.isToUpper ? Target.text.ToUpper() : Target.text, m_style);\n\n                //Move to new line and set following line height\n                _rect.y += singleLine + 1;\n                _rect.height = 1;\n            }\n            else\n            {\n                _rect.y += singleLine / 2f + 1;\n                _rect.height = 1;\n            }\n\n            m_style.normal.textColor = Target.colorText.ToColor();\n            // Color c = Target.colorText.ToColor();\n            // if (EditorGUIUtility.isProSkin)\n            // {\n            //     c = m_style.normal.textColor;\n            // }\n\n            //Draw spacer\n            UtilityDraw.CreateLineSpacer(EditorGUI.IndentedRect(_rect), Target.colorLine.ToColor(), _rect.height);\n        }\n\n        //How tall the GUI is for this decorator\n        public override float GetHeight()\n        {\n            return singleLine * 1.25f;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/HeaderLineDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e244a49e59664803b3397f5d84655d94\ntimeCreated: 1700193347"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/HelpDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n#if UNITY_EDITOR\n    [CustomPropertyDrawer(typeof(HelpBoxAttribute))]\n    public class HelpDrawer : PropertyDrawer\n    {\n        // Used for top and bottom padding between the text and the HelpBox border.\n        const int paddingHeight = 8;\n\n        // Used to add some margin between the the HelpBox and the property.\n        const int marginHeight = 2;\n\n        //  Global field to store the original (base) property height.\n        float baseHeight = 0;\n\n        // Custom added height for drawing text area which has the MultilineAttribute.\n        float addedHeight = 0;\n\n        /// <summary>\n        /// A wrapper which returns the PropertyDrawer.attribute field as a HelpAttribute.\n        /// </summary>\n        HelpBoxAttribute HelpBoxAttribute\n        {\n            get { return (HelpBoxAttribute)attribute; }\n        }\n\n        /// <summary>\n        /// A helper property to check for RangeAttribute.\n        /// </summary>\n        RangeAttribute rangeAttribute\n        {\n            get\n            {\n                var attributes = fieldInfo.GetCustomAttributes(typeof(RangeAttribute), true);\n                return attributes != null && attributes.Length > 0 ? (RangeAttribute)attributes[0] : null;\n            }\n        }\n\n        /// <summary>\n        /// A helper property to check for MultiLineAttribute.\n        /// </summary>\n        MultilineAttribute multilineAttribute\n        {\n            get\n            {\n                var attributes = fieldInfo.GetCustomAttributes(typeof(MultilineAttribute), true);\n                return attributes != null && attributes.Length > 0 ? (MultilineAttribute)attributes[0] : null;\n            }\n        }\n\n\n        public override float GetPropertyHeight(SerializedProperty prop, GUIContent label)\n        {\n            // We store the original property height for later use...\n            baseHeight = base.GetPropertyHeight(prop, label);\n\n            // This stops icon shrinking if text content doesn't fill out the container enough.\n            float minHeight = paddingHeight * 5;\n\n            // Calculate the height of the HelpBox using the GUIStyle on the current skin and the inspector\n            // window's currentViewWidth.\n            var content = new GUIContent(HelpBoxAttribute.text);\n            var style = GUI.skin.GetStyle(\"helpbox\");\n\n            var height = style.CalcHeight(content, EditorGUIUtility.currentViewWidth);\n\n            // We add tiny padding here to make sure the text is not overflowing the HelpBox from the top\n            // and bottom.\n            height += marginHeight * 2;\n\n            // Since we draw a custom text area with the label above if our property contains the\n            // MultilineAttribute, we need to add some extra height to compensate. This is stored in a\n            // seperate global field so we can use it again later.\n            if (multilineAttribute != null && prop.propertyType == SerializedPropertyType.String)\n            {\n                addedHeight = 48f;\n            }\n\n            // If the calculated HelpBox is less than our minimum height we use this to calculate the returned\n            // height instead.\n            return height > minHeight ? height + baseHeight + addedHeight : minHeight + baseHeight + addedHeight;\n        }\n\n\n        public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)\n        {\n            // We get a local reference to the MultilineAttribute as we use it twice in this method and it\n            // saves calling the logic twice for minimal optimization, etc...\n            var multiline = multilineAttribute;\n\n            EditorGUI.BeginProperty(position, label, prop);\n\n            // Copy the position out so we can calculate the position of our HelpBox without affecting the\n            // original position.\n            var helpPos = position;\n\n            helpPos.height -= baseHeight + marginHeight;\n\n\n            if (multiline != null)\n            {\n                helpPos.height -= addedHeight;\n            }\n\n            // Renders the HelpBox in the Unity inspector UI.\n            EditorGUI.HelpBox(helpPos, HelpBoxAttribute.text, HelpBoxAttribute.type);\n\n            position.y += helpPos.height + marginHeight;\n            position.height = baseHeight;\n\n\n            // If we have a RangeAttribute on our field, we need to handle the PropertyDrawer differently to\n            // keep the same style as Unity's default.\n            var range = rangeAttribute;\n\n            if (range != null)\n            {\n                if (prop.propertyType == SerializedPropertyType.Float)\n                {\n                    EditorGUI.Slider(position, prop, range.min, range.max, label);\n                }\n                else if (prop.propertyType == SerializedPropertyType.Integer)\n                {\n                    EditorGUI.IntSlider(position, prop, (int)range.min, (int)range.max, label);\n                }\n                else\n                {\n                    // Not numeric so draw standard property field as punishment for adding RangeAttribute to\n                    // a property which can not have a range :P\n                    EditorGUI.PropertyField(position, prop, label);\n                }\n            }\n            else if (multiline != null)\n            {\n                // Here's where we handle the PropertyDrawer differently if we have a MultiLineAttribute, to try\n                // and keep some kind of multiline text area. This is not identical to Unity's default but is\n                // better than nothing...\n                if (prop.propertyType == SerializedPropertyType.String)\n                {\n                    var style = GUI.skin.label;\n                    var size = style.CalcHeight(label, EditorGUIUtility.currentViewWidth);\n\n                    EditorGUI.LabelField(position, label);\n\n                    position.y += size;\n                    position.height += addedHeight - size;\n\n                    // Fixed text dissappearing thanks to: http://answers.unity3d.com/questions/244043/textarea-does-not-work-text-dissapears-solution-is.html\n                    prop.stringValue = EditorGUI.TextArea(position, prop.stringValue);\n                }\n                else\n                {\n                    // Again with a MultilineAttribute on a non-text field deserves for the standard property field\n                    // to be drawn as punishment :P\n                    EditorGUI.PropertyField(position, prop, label);\n                }\n            }\n            else\n            {\n                // If we get to here it means we're drawing the default property field below the HelpBox. More custom\n                // and built in PropertyDrawers could be implemented to enable HelpBox but it could easily make for\n                // hefty else/if block which would need refactoring!\n                EditorGUI.PropertyField(position, prop, label);\n            }\n\n            EditorGUI.EndProperty();\n        }\n    }\n#else\n    // Replicate MessageType Enum if we are not in editor as this enum exists in UnityEditor namespace.\n    // This should stop errors being logged the same as Shawn Featherly's commit in the Github repo but I\n    // feel is cleaner than having the conditional directive in the middle of the HelpAttribute constructor.\n    public enum MessageType\n    {\n        None,\n        Info,\n        Warning,\n        Error,\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/HelpDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 184ad84ff1994cd9acb68ceb52fa5af8\ntimeCreated: 1700132045"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/HighlightDrawer.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing UnityEditor;\nusing System.Reflection;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    [CustomPropertyDrawer(typeof(HighlightAttribute))]\n    public class HighlightDrawer : PropertyDrawer\n    {\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            var highlightAttribute = attribute as HighlightAttribute;\n\n            bool doHighlight = true;\n\n            if (!string.IsNullOrEmpty(highlightAttribute.validateField))\n            {\n                var t = property.serializedObject.targetObject.GetType();\n                var methodInfo = t.GetMethod(highlightAttribute.validateField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n                var fieldInfo = t.GetField(highlightAttribute.validateField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n                var propertyInfo = t.GetProperty(highlightAttribute.validateField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n\n                if (methodInfo != null)\n                {\n                    doHighlight = (bool)methodInfo.Invoke(property.serializedObject.targetObject, null) == (bool)highlightAttribute.comparationValue;\n                    ;\n                }\n\n                // else\n                // {\n                //     Debug.LogError(\"Invalid Validate function: \" + highlightAttribute.ValidateField, property.serializedObject.targetObject);\n                // }\n                if (fieldInfo != null)\n                {\n                    SerializedProperty conditionField = property.serializedObject.FindProperty(highlightAttribute.validateField);\n                    // We check that exist a Field with the parameter name\n                    if (conditionField == null)\n                    {\n                        //ShowError(position, label, \"Error getting the condition Field. Check the name.\");\n                        return;\n                    }\n\n                    switch (conditionField.propertyType)\n                    {\n                        case SerializedPropertyType.Boolean:\n                            try\n                            {\n                                bool comparationValue = highlightAttribute.comparationValue == null || (bool)highlightAttribute.comparationValue;\n                                doHighlight = conditionField.boolValue == comparationValue;\n                            }\n                            catch\n                            {\n                                // ShowError(position, label, \"Invalid comparation Value Type\");\n                                return;\n                            }\n\n                            break;\n                        case SerializedPropertyType.Enum:\n                            object paramEnum = highlightAttribute.comparationValue;\n                            object[] paramEnumArray = highlightAttribute.comparationValueArray;\n\n                            if (paramEnum == null && paramEnumArray == null)\n                            {\n                                doHighlight = true;\n                                // ShowError(position, label, \"The comparation enum value is null\");\n                                return;\n                            }\n                            else if (UtilityDraw.IsEnum(paramEnum))\n                            {\n                                if (!UtilityDraw.CheckSameEnumType(new[] { paramEnum.GetType() }, property.serializedObject.targetObject.GetType(), conditionField.propertyPath))\n                                {\n                                    doHighlight = true;\n                                    //ShowError(position, label, \"Enum Types doesn't match\");\n                                    return;\n                                }\n                                else\n                                {\n                                    string enumValue = Enum.GetValues(paramEnum.GetType()).GetValue(conditionField.enumValueIndex).ToString();\n                                    if (paramEnum.ToString() != enumValue)\n                                        doHighlight = false;\n                                    else\n                                        doHighlight = true;\n                                }\n                            }\n                            else if (UtilityDraw.IsEnum(paramEnumArray))\n                            {\n                                if (!UtilityDraw.CheckSameEnumType(paramEnumArray.Select(x => x.GetType()), property.serializedObject.targetObject.GetType(),\n                                        conditionField.propertyPath))\n                                {\n                                    doHighlight = true;\n                                    //ShowError(position, label, \"Enum Types doesn't match\");\n                                    return;\n                                }\n                                else\n                                {\n                                    string enumValue = Enum.GetValues(paramEnumArray[0].GetType()).GetValue(conditionField.enumValueIndex).ToString();\n                                    if (paramEnumArray.All(x => x.ToString() != enumValue))\n                                        doHighlight = false;\n                                    else\n                                        doHighlight = true;\n                                }\n                            }\n                            else\n                            {\n                                doHighlight = true;\n                                //  ShowError(position, label, \"The comparation enum value is not an enum\");\n                                return;\n                            }\n\n                            break;\n                        case SerializedPropertyType.Integer:\n                        case SerializedPropertyType.Float:\n                            string stringValue;\n                            bool error = false;\n\n                            float conditionValue = 0;\n                            if (conditionField.propertyType == SerializedPropertyType.Integer)\n                                conditionValue = conditionField.intValue;\n                            else if (conditionField.propertyType == SerializedPropertyType.Float)\n                                conditionValue = conditionField.floatValue;\n\n                            try\n                            {\n                                stringValue = (string)highlightAttribute.comparationValue;\n                            }\n                            catch\n                            {\n                                doHighlight = true;\n                                //ShowError(position, label, \"Invalid comparation Value Type\");\n                                return;\n                            }\n\n                            if (stringValue.StartsWith(\"==\"))\n                            {\n                                float? value = UtilityDraw.GetValue(stringValue, \"==\");\n                                if (value == null)\n                                    error = true;\n                                else\n                                    doHighlight = conditionValue == value;\n                            }\n                            else if (stringValue.StartsWith(\"!=\"))\n                            {\n                                float? value = UtilityDraw.GetValue(stringValue, \"!=\");\n                                if (value == null)\n                                    error = true;\n                                else\n                                    doHighlight = conditionValue != value;\n                            }\n                            else if (stringValue.StartsWith(\"<=\"))\n                            {\n                                float? value = UtilityDraw.GetValue(stringValue, \"<=\");\n                                if (value == null)\n                                    error = true;\n                                else\n                                    doHighlight = conditionValue <= value;\n                            }\n                            else if (stringValue.StartsWith(\">=\"))\n                            {\n                                float? value = UtilityDraw.GetValue(stringValue, \">=\");\n                                if (value == null)\n                                    error = true;\n                                else\n                                    doHighlight = conditionValue >= value;\n                            }\n                            else if (stringValue.StartsWith(\"<\"))\n                            {\n                                float? value = UtilityDraw.GetValue(stringValue, \"<\");\n                                if (value == null)\n                                    error = true;\n                                else\n                                    doHighlight = conditionValue < value;\n                            }\n                            else if (stringValue.StartsWith(\">\"))\n                            {\n                                float? value = UtilityDraw.GetValue(stringValue, \">\");\n                                if (value == null)\n                                    error = true;\n                                else\n                                    doHighlight = conditionValue > value;\n                            }\n\n                            if (error)\n                            {\n                                doHighlight = true;\n                                // ShowError(position, label, \"Invalid comparation instruction for Int or float value\");\n                                return;\n                            }\n\n                            break;\n                        default:\n                            doHighlight = true;\n                            //  ShowError(position, label, \"This type has not supported.\");\n                            return;\n                    }\n                }\n                else if (propertyInfo != null)\n                {\n                    doHighlight = (bool)propertyInfo.GetValue(property.serializedObject.targetObject) == (bool)highlightAttribute.comparationValue;\n                }\n            }\n\n            if (doHighlight)\n            {\n                // get the highlight color\n                var color = ColorExtensions.ToColor(highlightAttribute.highColor);\n\n                // create a ractangle to draw the highlight to, slightly larger than our property\n                var padding = EditorGUIUtility.standardVerticalSpacing;\n                var highlightRect = new Rect(position.x - padding, position.y - padding,\n                    position.width + (padding * 2), position.height + (padding * 2));\n\n                // draw the highlight first\n                EditorGUI.DrawRect(highlightRect, color);\n\n                // make sure the propertys text is dark and easy to read over the bright highlight\n                var cc = GUI.contentColor;\n                GUI.contentColor = Color.black;\n\n                // draw the property ontop of the highlight\n                EditorGUI.PropertyField(position, property, label);\n\n                GUI.contentColor = cc;\n            }\n            else\n            {\n                EditorGUI.PropertyField(position, property, label);\n            }\n        }\n\n        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)\n        {\n            return EditorGUI.GetPropertyHeight(property, label, true);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/HighlightDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 038a4bb11bb84e6da267561eb762ba04\ntimeCreated: 1700214706"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/LayerAttributeDraw.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    [CustomPropertyDrawer(typeof(LayerAttribute))]\n    public class LayerAttributeDraw : PropertyDrawer\n    {\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            if (property.propertyType != SerializedPropertyType.Integer)\n            {\n                //Debug.LogWarning(\"Layer attribute must be used with 'int' property type\");\n                //base.OnGUI(position, property, label);\n                EditorGUI.LabelField(position, \"Layer attribute must be used with 'int' property type\", new GUIStyle { normal = new GUIStyleState { textColor = Color.yellow } });\n\n                return;\n            }\n\n            property.intValue = EditorGUI.LayerField(position, label, property.intValue);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/LayerAttributeDraw.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ae0951f67191478d99efd3b92319f6a3\ntimeCreated: 1700035279"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/TagAttributeDraw.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    [CustomPropertyDrawer(typeof(TagAttribute))]\n    public class TagAttributeDraw : PropertyDrawer\n    {\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            if (property.propertyType != SerializedPropertyType.String)\n            {\n                //Debug.LogWarning(\"Tag attribute must be used with 'string' property type\");\n                //base.OnGUI(position, property, label);\n                EditorGUI.LabelField(position, \"Tag attribute must be used with 'string' property type\", new GUIStyle { normal = new GUIStyleState { textColor = Color.yellow } });\n                return;\n            }\n\n            if (property.stringValue == \"\")\n            {\n                property.stringValue = UnityEditorInternal.InternalEditorUtility.tags[0];\n            }\n\n            property.stringValue = EditorGUI.TagField(position, label, property.stringValue);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/TagAttributeDraw.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 13463e988ddc4f80a546b417f0c2f3b6\ntimeCreated: 1700034947"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/TitleColorAttributeDrawer.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    [CustomPropertyDrawer(typeof(TitleColorAttribute))]\n    public class TitleColorAttributeDrawer : DecoratorDrawer\n    {\n        private float _nestedMinimumXPosition = 18f;\n        private float _paddingRightLine = 10f;\n\n        public override float GetHeight()\n        {\n            TitleColorAttribute titleColorAttribute = (TitleColorAttribute)attribute;\n            return titleColorAttribute.Spacing + titleColorAttribute.LineHeight + titleColorAttribute.Spacing;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            Rect rect = EditorGUI.IndentedRect(position);\n            rect.y += EditorGUIUtility.singleLineHeight / 2f;\n            TitleColorAttribute titleColorAttribute = (TitleColorAttribute)attribute;\n            Color lineColor = titleColorAttribute.LineColor.ToColor();\n\n            if (string.IsNullOrEmpty(titleColorAttribute.Title))\n            {\n                rect.height = titleColorAttribute.LineHeight;\n                EditorGUI.DrawRect(rect, lineColor);\n                return;\n            }\n\n            // Label style\n            GUIStyle style = new GUIStyle(EditorStyles.label) { richText = true };\n            style.stretchWidth = true;\n            style.clipping = TextClipping.Overflow;\n            GUIContent label = new GUIContent($\"<color=#{titleColorAttribute.TitleColorString}><b>{titleColorAttribute.Title}</b></color>\");\n            Vector2 textSize = style.CalcSize(label);\n\n            float linesRectWidth = (position.width - textSize.x) / 2f;\n            float labelPaddingSize = 5f;\n\n            if (titleColorAttribute.AlignTitleLeft)\n            {\n                var rigthLinePositionX = position.xMin + textSize.x + labelPaddingSize + _paddingRightLine;\n\n                Rect labelLeftRect = new Rect(position.xMin, position.yMin - (titleColorAttribute.Spacing * 0.01f), textSize.x, position.height);\n\n                if (rect.xMin > _nestedMinimumXPosition)\n                {\n                    rigthLinePositionX = labelLeftRect.xMax + labelPaddingSize * 2 + (rect.xMin / 2f);\n                }\n\n                Rect RightRect = new Rect(rigthLinePositionX, position.yMin + titleColorAttribute.Spacing, position.width - textSize.x - 10f, titleColorAttribute.LineHeight);\n\n                EditorGUI.LabelField(labelLeftRect, label, style);\n                EditorGUI.DrawRect(RightRect, lineColor);\n                return;\n            }\n\n            Rect leftLineRect = new Rect(position.xMin, position.yMin + titleColorAttribute.Spacing, linesRectWidth, titleColorAttribute.LineHeight);\n\n            var labelPositionX = leftLineRect.xMax + labelPaddingSize;\n            var rightLineRectWidth = linesRectWidth - _paddingRightLine;\n\n            // If the rect is nested inside a list or an object's property\n            if (rect.xMin > _nestedMinimumXPosition)\n            {\n                labelPositionX = leftLineRect.xMax - (rect.xMin / 2f);\n                rightLineRectWidth = linesRectWidth;\n            }\n\n            Rect labelRect = new Rect(labelPositionX, position.yMin - (titleColorAttribute.Spacing * 0.01f), textSize.x, position.height);\n\n            var rightLinePositionX = rect.xMin > _nestedMinimumXPosition ? labelRect.xMax + labelPaddingSize * 2 + (rect.xMin / 2f) : labelRect.xMax + labelPaddingSize;\n\n            Rect rightLineRect = new Rect(rightLinePositionX, position.yMin + titleColorAttribute.Spacing, rightLineRectWidth, titleColorAttribute.LineHeight);\n\n            EditorGUI.DrawRect(leftLineRect, lineColor);\n            EditorGUI.LabelField(labelRect, label, style);\n            EditorGUI.DrawRect(rightLineRect, lineColor);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/TitleColorAttributeDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 7592c31d65ed40bb84faca2bbdaf3104\ntimeCreated: 1700209364"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/UtilityDraw.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public static class UtilityDraw\n    {\n        /// <summary>\n        /// Return if the object is enum and not null\n        /// </summary>\n        public static bool IsEnum(object obj)\n        {\n            return obj != null && obj.GetType().IsEnum;\n        }\n\n        /// <summary>\n        /// Return if all the objects are enums and not null\n        /// </summary>\n        public static bool IsEnum(object[] obj)\n        {\n            return obj != null && obj.All(o => o.GetType().IsEnum);\n        }\n\n        /// <summary>\n        /// Check if the field with name \"fieldName\" has the same class as the \"checkTypes\" classes through reflection\n        /// </summary>\n        public static bool CheckSameEnumType(IEnumerable<Type> checkTypes, Type classType, string fieldName)\n        {\n            string[] fieldNames = fieldName.Split('.');\n            Type currentType = classType;\n\n            foreach (var name in fieldNames)\n            {\n                FieldInfo field = currentType.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n                PropertyInfo property = currentType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n\n                if (field != null)\n                {\n                    currentType = field.FieldType;\n                }\n                else if (property != null)\n                {\n                    currentType = property.PropertyType;\n                }\n                else\n                {\n                    return false;\n                }\n            }\n\n            return checkTypes.All(x => x == currentType);\n        }\n\n        /// <summary>\n        /// Return the float value in the content string removing the remove string\n        /// </summary>\n        public static float? GetValue(string content, string remove)\n        {\n            string removed = content.Replace(remove, \"\");\n            try\n            {\n                return float.Parse(removed);\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        public static void CreateLineSpacer(Rect _rect, Color _color, float _height = 2)\n        {\n            _rect.height = _height;\n\n            Color oldColour = GUI.color;\n\n            GUI.color = _color;\n            EditorGUI.DrawRect(_rect, _color);\n            GUI.color = oldColour;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw/UtilityDraw.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 90c43d5003974388a0c80118cb2e7170\ntimeCreated: 1700161538"
  },
  {
    "path": "VirtueSky/Inspector/Editor/CustomizeDraw.meta",
    "content": "fileFormatVersion: 2\nguid: 6bc1040c970fb164bb6fc07f5f9d0bf8\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriEditor.cs",
    "content": "using UnityEditor;\nusing UnityEngine.UIElements;\n\nnamespace VirtueSky.Inspector.Editors\n{\n    public abstract class TriEditor : Editor\n    {\n        private TriEditorCore _core;\n\n        protected virtual void OnEnable()\n        {\n            _core = new TriEditorCore(this);\n        }\n\n        protected virtual void OnDisable()\n        {\n            _core.Dispose();\n        }\n\n\n        public override void OnInspectorGUI()\n        {\n            _core.OnInspectorGUI();\n        }\n\n        public override VisualElement CreateInspectorGUI()\n        {\n            return _core.CreateVisualElement();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7985f723508b7434183568ca5c8436bd\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriEditorCore.cs",
    "content": "﻿using System.Collections.Generic;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.UIElements;\n\nnamespace VirtueSky.Inspector.Editors\n{\n    public class TriEditorCore\n    {\n        public static readonly Dictionary<TriPropertyTree, VisualElement> UiElementsRoots\n            = new Dictionary<TriPropertyTree, VisualElement>();\n\n        private readonly Editor _editor;\n\n        private TriPropertyTreeForSerializedObject _inspector;\n\n        public TriEditorCore(Editor editor)\n        {\n            _editor = editor;\n        }\n\n        public void Dispose()\n        {\n            if (_inspector != null)\n            {\n                UiElementsRoots.Remove(_inspector);\n\n                _inspector.Dispose();\n            }\n\n            _inspector = null;\n        }\n\n        public void OnInspectorGUI(VisualElement visualRoot = null)\n        {\n            var serializedObject = _editor.serializedObject;\n\n            if (serializedObject.targetObjects.Length == 0)\n            {\n                return;\n            }\n\n            if (serializedObject.targetObject == null)\n            {\n                EditorGUILayout.HelpBox(\"Script is missing\", MessageType.Warning);\n                return;\n            }\n\n            foreach (var targetObject in serializedObject.targetObjects)\n            {\n                if (TriGuiHelper.IsEditorTargetPushed(targetObject))\n                {\n                    GUILayout.Label(\"Recursive inline editors not supported\");\n                    return;\n                }\n            }\n\n            if (_inspector == null)\n            {\n                _inspector = new TriPropertyTreeForSerializedObject(serializedObject);\n            }\n\n            if (visualRoot != null)\n            {\n                UiElementsRoots[_inspector] = visualRoot;\n            }\n\n            serializedObject.UpdateIfRequiredOrScript();\n\n            _inspector.Update();\n            _inspector.RunValidationIfRequired();\n\n            EditorGUIUtility.hierarchyMode = false;\n\n            using (TriGuiHelper.PushEditorTarget(serializedObject.targetObject))\n            {\n                _inspector.Draw();\n            }\n\n            if (serializedObject.ApplyModifiedProperties())\n            {\n                _inspector.RequestValidation();\n            }\n\n            if (_inspector.RepaintRequired)\n            {\n                _editor.Repaint();\n            }\n        }\n\n        public VisualElement CreateVisualElement()\n        {\n            var container = new VisualElement();\n            var root = new VisualElement()\n            {\n                style =\n                {\n                    position = Position.Absolute,\n                },\n            };\n\n            container.Add(new IMGUIContainer(() =>\n            {\n                const float labelExtraPadding = 2;\n                const float labelWidthRatio = 0.45f;\n                const float labelMinWidth = 120;\n\n                var space = container.resolvedStyle.left + container.resolvedStyle.right + labelExtraPadding;\n\n                EditorGUIUtility.wideMode = true;\n                EditorGUIUtility.hierarchyMode = false;\n                EditorGUIUtility.labelWidth = Mathf.Max(labelMinWidth,\n                    container.resolvedStyle.width * labelWidthRatio - space);\n\n                GUILayout.BeginVertical(Styles.RootLayout);\n                OnInspectorGUI(root);\n                GUILayout.EndVertical();\n            })\n            {\n                style =\n                {\n                    marginLeft = -Styles.RootMarginLeft,\n                    marginRight = -Styles.RootMarginRight,\n                },\n            });\n\n            container.Add(root);\n\n            return container;\n        }\n\n        private static class Styles\n        {\n            public const int RootMarginLeft = 15;\n            public const int RootMarginRight = 6;\n\n            public static readonly GUIStyle RootLayout = new GUIStyle\n            {\n                padding = new RectOffset(RootMarginLeft, RootMarginRight, 0, 0),\n            };\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriEditorCore.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a7bd33877ecd42dc878e2b28f0a9f581\ntimeCreated: 1694856077"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriMonoBehaviourEditor.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Editors\n{\n    [CanEditMultipleObjects]\n    [CustomEditor(typeof(MonoBehaviour), editorForChildClasses: true, isFallback = true)]\n    internal sealed class TriMonoBehaviourEditor : TriEditor\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriMonoBehaviourEditor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ebc893dd0ca44a789a00c03f7a71dc56\ntimeCreated: 1683784191"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriScriptableObjectEditor.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Editors\n{\n    [CanEditMultipleObjects]\n    [CustomEditor(typeof(ScriptableObject), editorForChildClasses: true, isFallback = true)]\n    internal sealed class TriScriptableObjectEditor : TriEditor\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriScriptableObjectEditor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 5fe6a72a9e734fcc8ab5f29cd13c9d53\ntimeCreated: 1683784197"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriScriptedImporterEditor.cs",
    "content": "﻿using VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEngine.UIElements;\n\n#if UNITY_2020_2_OR_NEWER\nusing UnityEditor.AssetImporters;\n#else\nusing UnityEditor.Experimental.AssetImporters;\n#endif\n\nnamespace VirtueSky.Inspector.Editors\n{\n    [CanEditMultipleObjects]\n    [CustomEditor(typeof(ScriptedImporter), editorForChildClasses: true)]\n    public sealed class TriScriptedImporterEditor : ScriptedImporterEditor\n    {\n        private TriEditorCore _core;\n\n        public override void OnEnable()\n        {\n            base.OnEnable();\n\n            _core = new TriEditorCore(this);\n        }\n\n        public override void OnDisable()\n        {\n            _core.Dispose();\n\n            base.OnDisable();\n        }\n\n        public override void OnInspectorGUI()\n        {\n            _core.OnInspectorGUI();\n\n            ApplyRevertGUI();\n        }\n\n        public override VisualElement CreateInspectorGUI()\n        {\n            var root = new VisualElement();\n\n            root.Add(_core.CreateVisualElement());\n            root.Add(new IMGUIContainer(() => DoImporterDefaultGUI()));\n\n            return root;\n        }\n\n        private void DoImporterDefaultGUI()\n        {\n            if (extraDataType != null)\n            {\n                EditorProxy.DoDrawDefaultInspector(extraDataSerializedObject);\n            }\n\n            ApplyRevertGUI();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriScriptedImporterEditor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 421d7c27350d45308b6a91b76560bb50\ntimeCreated: 1683784201"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriSettingsProvider.cs",
    "content": "﻿using UnityEditor;\n\nnamespace VirtueSky.Inspector.Editors\n{\n    public class TriSettingsProvider : SettingsProvider\n    {\n        private class Styles\n        {\n        }\n\n        public TriSettingsProvider()\n            : base(\"Project/Tri Inspector\", SettingsScope.Project)\n        {\n        }\n\n        public override void OnGUI(string searchContext)\n        {\n            EditorGUI.BeginDisabledGroup(EditorApplication.isCompiling);\n\n            base.OnGUI(searchContext);\n\n            EditorGUI.EndDisabledGroup();\n        }\n\n        [SettingsProvider]\n        public static SettingsProvider CreateTriInspectorSettingsProvider()\n        {\n            var provider = new TriSettingsProvider\n            {\n                keywords = GetSearchKeywordsFromGUIContentProperties<Styles>(),\n            };\n\n            return provider;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors/TriSettingsProvider.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e21ace13982a498283f60e3271c86551\ntimeCreated: 1651644353"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Editors.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d685f31e94904c5d9319405aa8b775f9\ntimeCreated: 1638856449"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/InlineEditorElement.cs",
    "content": "﻿using VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class InlineEditorElement : TriElement\n    {\n        private readonly TriProperty _property;\n        private readonly Props _props;\n        private Editor _editor;\n        private Rect _editorPosition;\n        private bool _dirty;\n\n        [System.Serializable]\n        public struct Props\n        {\n            public InlineEditorModes mode;\n            public float previewHeight;\n\n            public bool DrawGUI => (mode & InlineEditorModes.GUIOnly) != 0;\n            public bool DrawHeader => (mode & InlineEditorModes.Header) != 0;\n            public bool DrawPreview => (mode & InlineEditorModes.Preview) != 0;\n        }\n\n        public InlineEditorElement(TriProperty property, Props props = default)\n        {\n            _property = property;\n            _props = props;\n            _editorPosition = Rect.zero;\n        }\n\n        protected override void OnDetachFromPanel()\n        {\n            if (_editor != null)\n            {\n                Object.DestroyImmediate(_editor);\n            }\n\n            base.OnDetachFromPanel();\n        }\n\n        public override bool Update()\n        {\n            if (_editor == null || _editor.target != (Object) _property.Value)\n            {\n                if (_editor != null)\n                {\n                    Object.DestroyImmediate(_editor);\n                }\n\n                _dirty = true;\n            }\n\n            if (_dirty)\n            {\n                _dirty = false;\n                return true;\n            }\n\n            return false;\n        }\n\n        public override float GetHeight(float width)\n        {\n            if (_property.IsExpanded && !_property.IsValueMixed)\n            {\n                return _editorPosition.height;\n            }\n\n            return 0f;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (Event.current.type == EventType.Repaint)\n            {\n                _editorPosition = position;\n            }\n\n            var lastEditorRect = Rect.zero;\n            var shouldDrawEditor = _property.IsExpanded && !_property.IsValueMixed;\n\n            if (_editor == null && shouldDrawEditor && _property.Value is Object obj && obj != null)\n            {\n                _editor = Editor.CreateEditor(obj);\n\n                if (!InternalEditorUtilityProxy.GetIsInspectorExpanded(obj))\n                {\n                    InternalEditorUtilityProxy.SetIsInspectorExpanded(obj, true);\n                }\n            }\n\n            if (_editor != null && shouldDrawEditor)\n            {\n                GUILayout.BeginArea(_editorPosition);\n                GUILayout.BeginVertical();\n\n                if (_props.DrawHeader || _props.DrawGUI)\n                {\n                    GUILayout.BeginVertical();\n\n                    if (_props.DrawHeader)\n                    {\n                        GUILayout.BeginVertical();\n                        _editor.DrawHeader();\n                        GUILayout.EndVertical();\n                    }\n\n                    if (_props.DrawGUI)\n                    {\n                        GUILayout.BeginVertical();\n                        _editor.OnInspectorGUI();\n                        GUILayout.EndVertical();\n                    }\n\n                    GUILayout.EndVertical();\n                }\n\n                if (_props.DrawPreview && _editor.HasPreviewGUI())\n                {\n                    GUILayout.BeginVertical();\n\n                    var previewOpts = new[] {GUILayout.ExpandWidth(true), GUILayout.Height(_props.previewHeight),};\n                    var previewRect = EditorGUILayout.GetControlRect(false, _props.previewHeight, previewOpts);\n\n                    previewRect.width = Mathf.Max(previewRect.width, 10);\n                    previewRect.height = Mathf.Max(previewRect.height, 10);\n\n                    var guiEnabled = GUI.enabled;\n                    GUI.enabled = true;\n\n                    _editor.DrawPreview(previewRect);\n\n                    GUI.enabled = guiEnabled;\n\n                    GUILayout.EndVertical();\n                }\n\n                GUILayout.EndVertical();\n                lastEditorRect = GUILayoutUtility.GetLastRect();\n                GUILayout.EndArea();\n            }\n            else\n            {\n                if (_editor != null)\n                {\n                    Object.DestroyImmediate(_editor);\n                }\n            }\n\n            if (Event.current.type == EventType.Repaint &&\n                !Mathf.Approximately(_editorPosition.height, lastEditorRect.height))\n            {\n                _editorPosition.height = lastEditorRect.height;\n                _dirty = true;\n                _property.PropertyTree.RequestRepaint();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/InlineEditorElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e5abb7004e824b6d87bae69c80c8df1d\ntimeCreated: 1641802293"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriBoxGroupElement.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriBoxGroupElement : TriHeaderGroupBaseElement\n    {\n        private readonly Props _props;\n\n        private ValueResolver<string> _headerResolver;\n        [CanBeNull] private TriProperty _firstProperty;\n        [CanBeNull] private TriProperty _toggleProperty;\n\n        private bool _expanded;\n\n        [Serializable]\n        public new struct Props\n        {\n            public string title;\n            public TitleMode titleMode;\n            public bool expandedByDefault;\n            public bool hideIfChildrenInvisible;\n        }\n\n        public TriBoxGroupElement(Props props = default) : base(new TriHeaderGroupBaseElement.Props\n        {\n            hideIfChildrenInvisible = props.hideIfChildrenInvisible,\n        })\n        {\n            _props = props;\n            _expanded = _props.expandedByDefault;\n        }\n\n        protected override void AddPropertyChild(TriElement element, TriProperty property)\n        {\n            _firstProperty = property;\n            _headerResolver = ValueResolver.ResolveString(property.Definition, _props.title ?? \"\");\n            \n            if (_headerResolver.TryGetErrorString(out var error))\n            {\n                AddChild(new TriInfoBoxElement(error, TriMessageType.Error));\n            }\n            \n            if (_props.titleMode == TitleMode.Toggle)\n            {\n                if (_toggleProperty == null)\n                {\n                    if (property.ValueType == typeof(bool))\n                    {\n                        _toggleProperty = property;\n\n                        return;\n                    }\n                    \n                    if (property.ChildrenProperties?.Count > 0)\n                    {\n                        var childrenProperty = property.ChildrenProperties[0];\n\n                        if (childrenProperty.ValueType == typeof(bool))\n                        {\n                            _toggleProperty = childrenProperty;\n                        }\n                    }\n                }\n            }\n            \n            base.AddPropertyChild(element, property);\n        }\n\n        protected override float GetHeaderHeight(float width)\n        {\n            if (_props.titleMode == TitleMode.Hidden)\n            {\n                return 0f;\n            }\n\n            return base.GetHeaderHeight(width);\n        }\n\n        protected override float GetContentHeight(float width)\n        {\n            if (((_props.titleMode == TitleMode.Toggle && _props.expandedByDefault) || \n                 _props.titleMode == TitleMode.Foldout) && !_expanded)\n            {\n                return 0f;\n            }\n\n            return base.GetContentHeight(width);\n        }\n\n        protected override void DrawHeader(Rect position)\n        {\n            TriEditorGUI.DrawBox(position, TriEditorStyles.TabOnlyOne);\n\n            var headerLabelRect = new Rect(position)\n            {\n                xMin = position.xMin + 6,\n                xMax = position.xMax - 6,\n                yMin = position.yMin + 2,\n                yMax = position.yMax - 2,\n            };\n\n            var headerContent = _headerResolver.GetValue(_firstProperty);\n\n            switch (_props.titleMode)\n            {\n                case TitleMode.Foldout:\n                    _expanded = EditorGUI.Foldout(headerLabelRect, _expanded, headerContent, true);\n                    break;\n                case TitleMode.Toggle:\n                {\n                    if (_toggleProperty?.Value is bool cachedValue)\n                    {\n                        var newValue = EditorGUI.ToggleLeft(headerLabelRect, headerContent, cachedValue);\n                    \n                        if (newValue != cachedValue)\n                        {\n                            _toggleProperty.SetValue(newValue);\n                        }\n                    \n                        _expanded = newValue;\n                    }\n                    else\n                    {\n                        EditorGUI.LabelField(headerLabelRect, $\"The first property in the group must be of bool.\");\n                    }\n                    break;\n                }\n                default:\n                    EditorGUI.LabelField(headerLabelRect, headerContent);\n                    break;\n            }\n        }\n\n        protected override void DrawContent(Rect position)\n        {\n            if (_props.titleMode == TitleMode.Foldout && !_expanded)\n            {\n                return;\n            }\n\n            if (_props.titleMode == TitleMode.Toggle && !_props.expandedByDefault && !_expanded)\n            {\n                EditorGUI.BeginDisabledGroup(true);\n                base.DrawContent(position);\n                EditorGUI.EndDisabledGroup();\n\n                return;\n\n            }\n\n            base.DrawContent(position);\n        }\n\n        public enum TitleMode\n        {\n            Normal,\n            Hidden,\n            Foldout,\n            Toggle,\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriBoxGroupElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c7a787b7a5e844a2a12192a9d52984b0\ntimeCreated: 1641802243"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriBuiltInPropertyElement.cs",
    "content": "﻿using VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriBuiltInPropertyElement : TriElement\n    {\n        private readonly TriProperty _property;\n        private readonly PropertyHandlerProxy _propertyHandler;\n        private readonly SerializedProperty _serializedProperty;\n\n        public TriBuiltInPropertyElement(\n            TriProperty property,\n            SerializedProperty serializedProperty,\n            PropertyHandlerProxy propertyHandler)\n        {\n            _property = property;\n            _serializedProperty = serializedProperty;\n            _propertyHandler = propertyHandler;\n        }\n\n        public override float GetHeight(float width)\n        {\n            return _propertyHandler.GetHeight(_serializedProperty, _property.DisplayNameContent, true);\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            EditorGUI.BeginChangeCheck();\n\n            if (_property.IsArrayElement &&\n                _serializedProperty.propertyType == SerializedPropertyType.Generic &&\n                _serializedProperty.hasVisibleChildren)\n            {\n                position.xMin += 12;\n            }\n\n            _propertyHandler.OnGUI(position, _serializedProperty, _property.DisplayNameContent, true);\n\n            if (EditorGUI.EndChangeCheck())\n            {\n                _property.NotifyValueChanged();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriBuiltInPropertyElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: cb76597978d84d19a27f6e8596e1a4bf\ntimeCreated: 1638774260"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriDropdownElement.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriDropdownElement : TriElement\n    {\n        private readonly TriProperty _property;\n        private readonly Func<TriProperty, IEnumerable<ITriDropdownItem>> _valuesGetter;\n\n        private object _currentValue;\n        private string _currentText;\n\n        private bool _hasNextValue;\n        private object _nextValue;\n\n        public TriDropdownElement(TriProperty property, Func<TriProperty, IEnumerable<ITriDropdownItem>> valuesGetter)\n        {\n            _property = property;\n            _valuesGetter = valuesGetter;\n        }\n\n        public override float GetHeight(float width)\n        {\n            return EditorGUIUtility.singleLineHeight;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (_hasNextValue)\n            {\n                var nextValue = _nextValue;\n                _hasNextValue = false;\n                _nextValue = null;\n\n                _property.SetValue(nextValue);\n                GUI.changed = true;\n            }\n\n            if (!_property.Comparer.Equals(_currentValue, _property.Value))\n            {\n                _currentValue = _property.Value;\n                _currentText = _valuesGetter.Invoke(_property)\n                    .FirstOrDefault(it => _property.Comparer.Equals(it.Value, _property.Value))\n                    ?.Text ?? (_property.Value?.ToString() ?? string.Empty);\n            }\n\n            var controlId = GUIUtility.GetControlID(FocusType.Passive);\n            position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent);\n\n            if (GUI.Button(position, _currentText, EditorStyles.popup))\n            {\n                ShowDropdown(position);\n            }\n        }\n\n        private void ShowDropdown(Rect position)\n        {\n            var items = _valuesGetter.Invoke(_property);\n            var menu = new GenericMenu();\n\n            foreach (var item in items)\n            {\n                var isOn = _property.Comparer.Equals(item.Value, _property.Value);\n                menu.AddItem(new GUIContent(item.Text), isOn, ChangeValue, item.Value);\n            }\n\n            menu.DropDown(position);\n\n            void ChangeValue(object v)\n            {\n                _nextValue = v;\n                _hasNextValue = true;\n                _property.PropertyTree.RequestRepaint();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriDropdownElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0bfe47c1836e47c48920fb74982c89cb\ntimeCreated: 1657812638"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriFoldoutElement.cs",
    "content": "﻿using VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    internal class TriFoldoutElement : TriPropertyCollectionBaseElement\n    {\n        private readonly TriProperty _property;\n\n        public TriFoldoutElement(TriProperty property)\n        {\n            _property = property;\n\n            DeclareGroups(property.ValueType);\n        }\n\n        public override bool Update()\n        {\n            var dirty = false;\n\n            if (_property.IsExpanded)\n            {\n                dirty |= GenerateChildren();\n            }\n            else\n            {\n                dirty |= ClearChildren();\n            }\n\n            dirty |= base.Update();\n\n            return dirty;\n        }\n\n        public override float GetHeight(float width)\n        {\n            var height = EditorGUIUtility.singleLineHeight;\n\n            if (!_property.IsExpanded)\n            {\n                return height;\n            }\n\n            height += base.GetHeight(width);\n\n            return height;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            var headerRect = new Rect(position)\n            {\n                height = EditorGUIUtility.singleLineHeight,\n            };\n            var contentRect = new Rect(position)\n            {\n                yMin = position.yMin + headerRect.height,\n            };\n\n            TriEditorGUI.Foldout(headerRect, _property);\n\n            if (!_property.IsExpanded)\n            {\n                return;\n            }\n\n            using (var indentedRectScope = TriGuiHelper.PushIndentedRect(contentRect, 1))\n            {\n                base.OnGUI(indentedRectScope.IndentedRect);\n            }\n        }\n\n        private bool GenerateChildren()\n        {\n            if (ChildrenCount != 0)\n            {\n                return false;\n            }\n\n            foreach (var childProperty in _property.ChildrenProperties)\n            {\n                AddProperty(childProperty);\n            }\n\n            return true;\n        }\n\n        private bool ClearChildren()\n        {\n            if (ChildrenCount == 0)\n            {\n                return false;\n            }\n\n            RemoveAllChildren();\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriFoldoutElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 90b64b1805694cf8999a0380d4ca70b6\ntimeCreated: 1638772042"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriHeaderGroupBaseElement.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public abstract class TriHeaderGroupBaseElement : TriPropertyCollectionBaseElement\n    {\n        private readonly Props _props;\n        private const float InsetTop = 4;\n        private const float InsetBottom = 4;\n        private const float InsetLeft = 4;\n        private const float InsetRight = 4;\n\n        private readonly List<TriProperty> _properties = new List<TriProperty>();\n\n        private bool IsAnyPropertyVisible => _properties.Any(it => it.IsVisible);\n\n        [Serializable]\n        public struct Props\n        {\n            public bool hideIfChildrenInvisible;\n        }\n\n        protected TriHeaderGroupBaseElement(Props props = default)\n        {\n            _props = props;\n        }\n        \n        protected override void AddPropertyChild(TriElement element, TriProperty property)\n        {\n            _properties.Add(property);\n\n            base.AddPropertyChild(element, property);\n        }\n\n        protected virtual float GetHeaderHeight(float width)\n        {\n            return 22;\n        }\n\n        protected virtual float GetContentHeight(float width)\n        {\n            return base.GetHeight(width);\n        }\n\n        protected virtual void DrawHeader(Rect position)\n        {\n        }\n\n        protected virtual void DrawContent(Rect position)\n        {\n            base.OnGUI(position);\n        }\n\n        public sealed override float GetHeight(float width)\n        {\n            if (_props.hideIfChildrenInvisible && !IsAnyPropertyVisible)\n            {\n                return -EditorGUIUtility.standardVerticalSpacing;\n            }\n\n            var headerHeight = GetHeaderHeight(width);\n            var contentHeight = GetContentHeight(width);\n\n            var height = headerHeight + contentHeight;\n\n            if (contentHeight > 0)\n            {\n                height += InsetTop + InsetBottom;\n            }\n\n            return height;\n        }\n\n        public sealed override void OnGUI(Rect position)\n        {\n            if (_props.hideIfChildrenInvisible && !IsAnyPropertyVisible)\n            {\n                return;\n            }\n\n            var headerHeight = GetHeaderHeight(position.width);\n            var contentHeight = GetContentHeight(position.width);\n\n            var headerBgRect = new Rect(position)\n            {\n                height = headerHeight,\n            };\n            var contentBgRect = new Rect(position)\n            {\n                yMin = headerBgRect.yMax,\n            };\n            var contentRect = new Rect(contentBgRect)\n            {\n                xMin = contentBgRect.xMin + InsetLeft,\n                xMax = contentBgRect.xMax - InsetRight,\n                yMin = contentBgRect.yMin + InsetTop,\n                yMax = contentBgRect.yMax - InsetBottom,\n                height = contentHeight,\n            };\n\n            if (headerHeight > 0f)\n            {\n                DrawHeader(headerBgRect);\n            }\n\n            if (contentHeight > 0)\n            {\n                TriEditorGUI.DrawBox(contentBgRect, headerHeight > 0f\n                    ? TriEditorStyles.ContentBox\n                    : TriEditorStyles.Box);\n\n                using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth - InsetLeft))\n                {\n                    DrawContent(contentRect);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriHeaderGroupBaseElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 7406688f5ef349a3ae0acee7ea9ec935\ntimeCreated: 1642760804"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriHorizontalGroupElement.cs",
    "content": "﻿using System;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriHorizontalGroupElement : TriPropertyCollectionBaseElement\n    {\n        private readonly float[] _sizes;\n        private readonly float _totalFixedSize;\n\n        public TriHorizontalGroupElement(float[] sizes = null)\n        {\n            _sizes = sizes ?? Array.Empty<float>();\n            _totalFixedSize = 0f;\n\n            for (var index = 0; index < _sizes.Length; index++)\n            {\n                if (TryGetFixedSizeByIndex(index, out var fixedSize))\n                {\n                    _totalFixedSize += fixedSize;\n                }\n            }\n        }\n\n        public override float GetHeight(float width)\n        {\n            if (ChildrenCount == 0)\n            {\n                return 0f;\n            }\n\n            var spacing = EditorGUIUtility.standardVerticalSpacing;\n            var totalSpacing = spacing * (ChildrenCount - 1);\n            var totalDynamic = width - totalSpacing - _totalFixedSize;\n            var dynamicChildCount = GetDynamicChildCount();\n\n            var height = 0f;\n\n            for (var i = 0; i < ChildrenCount; i++)\n            {\n                var childWidth = GetChildWidth(i, totalDynamic, dynamicChildCount);\n                var child = GetChild(i);\n                var childHeight = child.GetHeight(childWidth);\n\n                height = Mathf.Max(height, childHeight);\n            }\n\n            return height;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (ChildrenCount == 0)\n            {\n                return;\n            }\n\n            var spacing = EditorGUIUtility.standardVerticalSpacing;\n            var totalSpacing = spacing * (ChildrenCount - 1);\n            var totalDynamic = position.width - totalSpacing - _totalFixedSize;\n            var dynamicChildCount = GetDynamicChildCount();\n\n            var xOffset = 0f;\n            for (var i = 0; i < ChildrenCount; i++)\n            {\n                var childWidth = GetChildWidth(i, totalDynamic, dynamicChildCount);\n                var child = GetChild(i);\n                var childRect = new Rect(position)\n                {\n                    width = childWidth,\n                    height = child.GetHeight(childWidth),\n                    x = position.xMin + xOffset,\n                };\n\n                using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth / ChildrenCount))\n                {\n                    child.OnGUI(childRect);\n                }\n\n                xOffset += childWidth + spacing;\n            }\n        }\n\n        private float GetDynamicChildCount()\n        {\n            var count = 0f;\n\n            for (var i = 0; i < ChildrenCount; i++)\n            {\n                if (TryGetFixedSizeByIndex(i, out _))\n                {\n                    continue;\n                }\n\n                count++;\n            }\n\n            return count;\n        }\n\n        private float GetChildWidth(int i, float totalDynamic, float dynamicChildCount)\n        {\n            if (TryGetFixedSizeByIndex(i, out var fixedSize))\n            {\n                return fixedSize;\n            }\n\n            return totalDynamic / dynamicChildCount;\n        }\n\n        private bool TryGetFixedSizeByIndex(int index, out float fixedSize)\n        {\n            if (index < _sizes.Length && _sizes[index] > 0f)\n            {\n                fixedSize = _sizes[index];\n                return true;\n            }\n\n            fixedSize = 0f;\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriHorizontalGroupElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e609cf56a7e242d8b9cb5813178a7e69\ntimeCreated: 1642259149"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriInfoBoxElement.cs",
    "content": "﻿using System;\nusing VirtueSky.Inspector.Utilities;\nusing VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriInfoBoxElement : TriElement\n    {\n        private const int ActionSpacing = 5;\n        private const int ActionWidth = 100;\n        private const int ActionWidthWithSpacing = ActionWidth + ActionSpacing * 2;\n\n        private readonly GUIContent _message;\n        private readonly Texture2D _icon;\n        private readonly Color _color;\n        private readonly Action _inlineAction;\n        private readonly GUIContent _inlineActionContent;\n\n        public TriInfoBoxElement(string message, TriMessageType type = TriMessageType.None, Color? color = null,\n            Action inlineAction = null, GUIContent inlineActionContent = null)\n        {\n            var messageType = GetMessageType(type);\n            _icon = EditorGUIUtilityProxy.GetHelpIcon(messageType);\n            _message = new GUIContent(message);\n            _color = color ?? GetColor(type);\n            _inlineAction = inlineAction;\n            _inlineActionContent = inlineActionContent ?? GUIContent.none;\n        }\n\n        public override float GetHeight(float width)\n        {\n            var labelWidth = width;\n\n            if (_inlineAction != null)\n            {\n                labelWidth -= ActionWidthWithSpacing;\n            }\n\n            var style = _icon == null ? Styles.InfoBoxContentNone : Styles.InfoBoxContent;\n            var height = style.CalcHeight(_message, labelWidth);\n\n            if (_inlineAction != null)\n            {\n                height = Mathf.Max(height, CalcActionHeight() + ActionSpacing * 2);\n            }\n\n            return Mathf.Max(26, height);\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            using (TriGuiHelper.PushColor(_color))\n            {\n                GUI.Label(position, string.Empty, Styles.InfoBoxBg);\n            }\n\n            var labelWidth = position.width;\n\n            if (_inlineAction != null)\n            {\n                labelWidth -= ActionWidthWithSpacing;\n            }\n\n            if (_icon != null)\n            {\n                var labelRect = new Rect(position)\n                {\n                    width = labelWidth,\n                };\n\n                var iconRect = new Rect(position)\n                {\n                    xMin = position.xMin + 4,\n                    width = 20,\n                };\n\n                GUI.Label(labelRect, _message, Styles.InfoBoxContent);\n                GUI.DrawTexture(iconRect, _icon, ScaleMode.ScaleToFit);\n            }\n            else\n            {\n                GUI.Label(position, _message, Styles.InfoBoxContentNone);\n            }\n\n            if (_inlineAction != null)\n            {\n                var fixHeight = CalcActionHeight();\n\n                var actionRect = new Rect(position)\n                {\n                    xMax = position.xMax - ActionSpacing,\n                    xMin = position.xMax - ActionWidth - ActionSpacing,\n                    yMin = position.center.y - fixHeight / 2,\n                    yMax = position.center.y + fixHeight / 2,\n                };\n\n                if (GUI.Button(actionRect, _inlineActionContent, Styles.InfoBoxInlineAction))\n                {\n                    _inlineAction?.Invoke();\n                }\n            }\n        }\n\n\n        private float CalcActionHeight()\n        {\n            return Styles.InfoBoxInlineAction.CalcHeight(_inlineActionContent, ActionWidth);\n        }\n\n        private static Color GetColor(TriMessageType type)\n        {\n            switch (type)\n            {\n                case TriMessageType.Error:\n                    return new Color(1f, 0.4f, 0.4f);\n\n                case TriMessageType.Warning:\n                    return new Color(1f, 0.8f, 0.2f);\n\n                default:\n                    return Color.white;\n            }\n        }\n\n        private static MessageType GetMessageType(TriMessageType type)\n        {\n            switch (type)\n            {\n                case TriMessageType.None: return MessageType.None;\n                case TriMessageType.Info: return MessageType.Info;\n                case TriMessageType.Warning: return MessageType.Warning;\n                case TriMessageType.Error: return MessageType.Error;\n                default: return MessageType.None;\n            }\n        }\n\n        private static class Styles\n        {\n            public static readonly GUIStyle InfoBoxBg;\n            public static readonly GUIStyle InfoBoxContent;\n            public static readonly GUIStyle InfoBoxContentNone;\n            public static readonly GUIStyle InfoBoxInlineAction;\n\n            static Styles()\n            {\n                InfoBoxBg = new GUIStyle(EditorStyles.helpBox);\n                InfoBoxContentNone = new GUIStyle(EditorStyles.label)\n                {\n                    padding = new RectOffset(4, 4, 4, 4),\n                    fontSize = InfoBoxBg.fontSize,\n                    alignment = TextAnchor.MiddleLeft,\n                    wordWrap = true,\n                };\n                InfoBoxContent = new GUIStyle(InfoBoxContentNone)\n                {\n                    padding = new RectOffset(26, 4, 4, 4),\n                };\n                InfoBoxInlineAction = new GUIStyle(GUI.skin.button)\n                {\n                    wordWrap = true,\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriInfoBoxElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f64a66d501c34a808686c834530dd9a9\ntimeCreated: 1638860979"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriInlineGenericElement.cs",
    "content": "﻿using System;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    internal class TriInlineGenericElement : TriPropertyCollectionBaseElement\n    {\n        private readonly Props _props;\n        private readonly TriProperty _property;\n\n        [Serializable]\n        public struct Props\n        {\n            public bool drawPrefixLabel;\n            public float labelWidth;\n        }\n\n        public TriInlineGenericElement(TriProperty property, Props props = default)\n        {\n            _property = property;\n            _props = props;\n\n            DeclareGroups(property.ValueType);\n\n            foreach (var childProperty in property.ChildrenProperties)\n            {\n                AddProperty(childProperty);\n            }\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (_props.drawPrefixLabel)\n            {\n                var controlId = GUIUtility.GetControlID(FocusType.Passive);\n                position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent);\n            }\n\n            using (TriGuiHelper.PushLabelWidth(_props.labelWidth))\n            {\n                base.OnGUI(position);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriInlineGenericElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a5124d0a8d93488a858723d80fe69e69\ntimeCreated: 1638788657"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriLabelElement.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriLabelElement : TriElement\n    {\n        private readonly GUIContent _label;\n\n        public TriLabelElement(string label, string tooltip = \"\")\n        {\n            _label = new GUIContent(label, tooltip);\n        }\n\n        public TriLabelElement(GUIContent label)\n        {\n            _label = label;\n        }\n\n        public override float GetHeight(float width)\n        {\n            return GUI.skin.label.CalcHeight(_label, width);\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            GUI.Label(position, _label);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriLabelElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a193f4236257483a8d5a10f0025b3d4f\ntimeCreated: 1638771650"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriListElement.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Linq;\nusing VirtueSky.InspectorUnityInternalBridge;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.Inspector.Elements\n{\n     public class TriListElement : TriElement\n    {\n        private const int MinElementsForVirtualization = 25;\n\n        private const float ListExtraWidth = 7f;\n        private const float DraggableAreaExtraWidth = 14f;\n\n        private readonly TriProperty _property;\n        private readonly ReorderableList _reorderableListGui;\n        private readonly bool _alwaysExpanded;\n        private readonly bool _showElementLabels;\n        private readonly bool _showAlternatingBackground;\n\n        private float _lastContentWidth;\n        private int? _lastInvisibleElement;\n        private int? _lastVisibleElement;\n\n        protected ReorderableList ListGui => _reorderableListGui;\n\n        public TriListElement(TriProperty property)\n        {\n            property.TryGetAttribute(out ListDrawerSettingsAttribute settings);\n\n            _property = property;\n            _alwaysExpanded = settings?.AlwaysExpanded ?? false;\n            _showElementLabels = settings?.ShowElementLabels ?? false;\n            _showAlternatingBackground = settings?.ShowAlternatingBackground ?? true;\n            _reorderableListGui = new ReorderableList(null, _property.ArrayElementType)\n            {\n                showDefaultBackground = settings?.ShowDefaultBackground ?? true,\n                draggable = settings?.Draggable ?? true,\n                displayAdd = settings == null || !settings.HideAddButton,\n                displayRemove = settings == null || !settings.HideRemoveButton,\n                drawHeaderCallback = DrawHeaderCallback,\n                elementHeightCallback = ElementHeightCallback,\n                drawElementBackgroundCallback = DrawElementBackgroundCallback,\n                drawElementCallback = DrawElementCallback,\n                onAddCallback = AddElementCallback,\n                onRemoveCallback = RemoveElementCallback,\n                onReorderCallbackWithDetails = ReorderCallback,\n            };\n\n            if (!_reorderableListGui.displayAdd && !_reorderableListGui.displayRemove)\n            {\n                _reorderableListGui.footerHeight = 0f;\n            }\n        }\n\n        public override bool Update()\n        {\n            var dirty = false;\n\n            if (_property.TryGetSerializedProperty(out var serializedProperty) && serializedProperty.isArray)\n            {\n                _reorderableListGui.serializedProperty = serializedProperty;\n            }\n            else if (_property.Value != null)\n            {\n                _reorderableListGui.list = (IList) _property.Value;\n            }\n            else if (_reorderableListGui.list == null)\n            {\n                _reorderableListGui.list = (IList) (_property.FieldType.IsArray\n                    ? Array.CreateInstance(_property.ArrayElementType, 0)\n                    : Activator.CreateInstance(_property.FieldType));\n            }\n\n            if (_alwaysExpanded && !_property.IsExpanded)\n            {\n                _property.IsExpanded = true;\n            }\n\n            if (_property.IsExpanded)\n            {\n                dirty |= GenerateChildren();\n            }\n            else\n            {\n                dirty |= ClearChildren();\n            }\n\n            dirty |= base.Update();\n\n            if (dirty)\n            {\n                ReorderableListProxy.ClearCacheRecursive(_reorderableListGui);\n            }\n\n            return dirty;\n        }\n\n        public override float GetHeight(float width)\n        {\n            if (!_property.IsExpanded)\n            {\n                return _reorderableListGui.headerHeight + 4f;\n            }\n\n            _lastContentWidth = width;\n\n            return _reorderableListGui.GetHeight();\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (!_property.IsExpanded)\n            {\n                _lastInvisibleElement = null;\n                _lastVisibleElement = null;\n\n                ReorderableListProxy.DoListHeader(_reorderableListGui, new Rect(position)\n                {\n                    yMax = position.yMax - 4,\n                });\n                return;\n            }\n\n            if (_reorderableListGui.count < MinElementsForVirtualization)\n            {\n                _lastInvisibleElement = null;\n                _lastVisibleElement = null;\n            }\n\n            var labelWidthExtra = ListExtraWidth + DraggableAreaExtraWidth;\n\n            using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth - labelWidthExtra))\n            {\n                _reorderableListGui.DoList(position);\n            }\n        }\n\n        private void AddElementCallback(ReorderableList reorderableList)\n        {\n            AddElementCallback(reorderableList, null);\n        }\n\n        private void AddElementCallback(ReorderableList reorderableList, Object addedReferenceValue)\n        {\n            if (_property.TryGetSerializedProperty(out _))\n            {\n                ReorderableListProxy.DoAddButton(reorderableList, addedReferenceValue);\n                _property.NotifyValueChanged();\n                return;\n            }\n\n            var template = CloneValue(_property);\n\n            _property.SetValues(targetIndex =>\n            {\n                var value = (IList) _property.GetValue(targetIndex);\n\n                if (_property.FieldType.IsArray)\n                {\n                    var array = Array.CreateInstance(_property.ArrayElementType, template.Length + 1);\n                    Array.Copy(template, array, template.Length);\n\n                    if (addedReferenceValue != null)\n                    {\n                        array.SetValue(addedReferenceValue, array.Length - 1);\n                    }\n\n                    value = array;\n                }\n                else\n                {\n                    if (value == null)\n                    {\n                        value = (IList) Activator.CreateInstance(_property.FieldType);\n                    }\n\n                    var newElement = addedReferenceValue != null\n                        ? addedReferenceValue\n                        : CreateDefaultElementValue(_property);\n\n                    value.Add(newElement);\n                }\n\n                return value;\n            });\n        }\n\n        private void RemoveElementCallback(ReorderableList reorderableList)\n        {\n            if (_property.TryGetSerializedProperty(out _))\n            {\n                ReorderableListProxy.defaultBehaviours.DoRemoveButton(reorderableList);\n                _property.NotifyValueChanged();\n                return;\n            }\n\n            var template = CloneValue(_property);\n            var ind = reorderableList.index;\n\n            _property.SetValues(targetIndex =>\n            {\n                var value = (IList) _property.GetValue(targetIndex);\n\n                if (_property.FieldType.IsArray)\n                {\n                    var array = Array.CreateInstance(_property.ArrayElementType, template.Length - 1);\n                    Array.Copy(template, 0, array, 0, ind);\n                    Array.Copy(template, ind + 1, array, ind, array.Length - ind);\n                    value = array;\n                }\n                else\n                {\n                    value?.RemoveAt(ind);\n                }\n\n                return value;\n            });\n        }\n\n        private void ReorderCallback(ReorderableList list, int oldIndex, int newIndex)\n        {\n            if (_property.TryGetSerializedProperty(out _))\n            {\n                _property.NotifyValueChanged();\n                return;\n            }\n\n            var mainValue = _property.Value;\n\n            _property.SetValues(targetIndex =>\n            {\n                var value = (IList) _property.GetValue(targetIndex);\n\n                if (value == mainValue)\n                {\n                    return value;\n                }\n\n                var element = value[oldIndex];\n                for (var index = 0; index < value.Count - 1; ++index)\n                {\n                    if (index >= oldIndex)\n                    {\n                        value[index] = value[index + 1];\n                    }\n                }\n\n                for (var index = value.Count - 1; index > 0; --index)\n                {\n                    if (index > newIndex)\n                    {\n                        value[index] = value[index - 1];\n                    }\n                }\n\n                value[newIndex] = element;\n\n                return value;\n            });\n        }\n\n        private void SetArraySizeCallback(int arraySize)\n        {\n            if (arraySize < 0)\n            {\n                return;\n            }\n\n            if (_property.TryGetSerializedProperty(out var serializedProperty))\n            {\n                serializedProperty.arraySize = arraySize;\n                _property.NotifyValueChanged();\n                return;\n            }\n\n            var template = CloneValue(_property);\n\n            _property.SetValues(targetIndex =>\n            {\n                var value = (IList) _property.GetValue(targetIndex);\n\n                if (_property.FieldType.IsArray)\n                {\n                    var array = Array.CreateInstance(_property.ArrayElementType, arraySize);\n                    Array.Copy(template, array, Math.Min(arraySize, template.Length));\n\n                    value = array;\n                }\n                else\n                {\n                    if (value == null)\n                    {\n                        value = (IList) Activator.CreateInstance(_property.FieldType);\n                    }\n\n                    while (value.Count > arraySize)\n                    {\n                        value.RemoveAt(value.Count - 1);\n                    }\n\n                    while (value.Count < arraySize)\n                    {\n                        var newElement = CreateDefaultElementValue(_property);\n                        value.Add(newElement);\n                    }\n                }\n\n                return value;\n            });\n        }\n\n        private bool GenerateChildren()\n        {\n            var count = _reorderableListGui.count;\n\n            if (ChildrenCount == count)\n            {\n                return false;\n            }\n\n            while (ChildrenCount < count)\n            {\n                var property = _property.ArrayElementProperties[ChildrenCount];\n                AddChild(CreateItemElement(property));\n            }\n\n            while (ChildrenCount > count)\n            {\n                RemoveChildAt(ChildrenCount - 1);\n            }\n\n            return true;\n        }\n\n        private bool ClearChildren()\n        {\n            if (ChildrenCount == 0)\n            {\n                return false;\n            }\n\n            RemoveAllChildren();\n\n            return true;\n        }\n\n        protected virtual TriElement CreateItemElement(TriProperty property)\n        {\n            return new TriPropertyElement(property, new TriPropertyElement.Props\n            {\n                forceInline = !_showElementLabels,\n            });\n        }\n\n        private void DrawHeaderCallback(Rect rect)\n        {\n            var labelRect = new Rect(rect)\n            {\n                xMax = rect.xMax - 50,\n            };\n            var arraySizeRect = new Rect(rect)\n            {\n                xMin = labelRect.xMax,\n            };\n\n            if (_alwaysExpanded)\n            {\n                EditorGUI.LabelField(labelRect, _property.DisplayNameContent);\n            }\n            else\n            {\n                TriEditorGUI.Foldout(labelRect, _property);\n            }\n\n            EditorGUI.BeginChangeCheck();\n\n            var newArraySize = EditorGUI.DelayedIntField(arraySizeRect, _reorderableListGui.count);\n\n            if (EditorGUI.EndChangeCheck())\n            {\n                SetArraySizeCallback(newArraySize);\n                return;\n            }\n\n            if (Event.current.type == EventType.DragUpdated && rect.Contains(Event.current.mousePosition))\n            {\n                DragAndDrop.visualMode = DragAndDrop.objectReferences.All(obj => TryGetDragAndDropObject(obj, out _))\n                    ? DragAndDropVisualMode.Copy\n                    : DragAndDropVisualMode.Rejected;\n\n                Event.current.Use();\n            }\n            else if (Event.current.type == EventType.DragPerform && rect.Contains(Event.current.mousePosition))\n            {\n                DragAndDrop.AcceptDrag();\n\n                foreach (var obj in DragAndDrop.objectReferences)\n                {\n                    if (TryGetDragAndDropObject(obj, out var addedReferenceValue))\n                    {\n                        AddElementCallback(_reorderableListGui, addedReferenceValue);\n                    }\n                }\n\n                Event.current.Use();\n            }\n        }\n        \n        private void DrawElementBackgroundCallback(Rect rect, int index, bool isActive, bool isFocused)\n        {\n            if (_lastInvisibleElement.HasValue && index + 1 < _lastInvisibleElement.Value ||\n                _lastVisibleElement.HasValue && index - 1 > _lastVisibleElement.Value)\n            {\n                if (index != _reorderableListGui.index)\n                {\n                    return;\n                }\n            }\n\n            if (_showAlternatingBackground && index % 2 != 0)\n            {\n                EditorGUI.DrawRect(rect, new Color(0.1f, 0.1f, 0.1f, 0.15f));\n            }\n\n            ReorderableList.defaultBehaviours.DrawElementBackground(rect, index, isActive, isFocused,\n                _reorderableListGui.draggable);\n        }\n\n        private void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused)\n        {\n            if (index >= ChildrenCount)\n            {\n                return;\n            }\n\n            if (_lastInvisibleElement.HasValue && index + 1 < _lastInvisibleElement.Value ||\n                _lastVisibleElement.HasValue && index - 1 > _lastVisibleElement.Value)\n            {\n                if (index != _reorderableListGui.index)\n                {\n                    return;\n                }\n            }\n\n            if (_reorderableListGui.count > MinElementsForVirtualization)\n            {\n                if (Event.current.type == EventType.Repaint)\n                {\n                    var windowRect = GUIClipProxy.VisibleRect;\n                    var rectInWindow = GUIClipProxy.UnClipToWindow(rect);\n\n                    if (rectInWindow.yMax < 0)\n                    {\n                        _lastInvisibleElement = index;\n                    } else if (_lastInvisibleElement == index)\n                    {\n                        _lastInvisibleElement = index / 2;\n                        _lastVisibleElement = index / 2 + 1;\n                        _property.PropertyTree.RequestRepaint();\n                    }\n\n                    if (rectInWindow.y < windowRect.height)\n                    {\n                        if (!_lastVisibleElement.HasValue || index > _lastVisibleElement.Value)\n                        {\n                            _lastVisibleElement = index;\n                        }\n                    }\n                }\n            }\n\n            if (!_reorderableListGui.draggable)\n            {\n                rect.xMin += DraggableAreaExtraWidth;\n            }\n\n            using (TriPropertyOverrideContext.BeginOverride(ListPropertyOverrideContext.Instance))\n            {\n                GetChild(index).OnGUI(rect);\n            }\n        }\n\n        private float ElementHeightCallback(int index)\n        {\n            if (index >= ChildrenCount)\n            {\n                return EditorGUIUtility.singleLineHeight;\n            }\n\n            if (_lastInvisibleElement.HasValue && index + 1 < _lastInvisibleElement.Value ||\n                _lastVisibleElement.HasValue && index - 1 > _lastVisibleElement.Value)\n            {\n                if (index != _reorderableListGui.index)\n                {\n                    return Mathf.Max(EditorGUIUtility.singleLineHeight, GetChild(index).CachedHeight);\n                }\n            }\n\n            return GetChild(index).GetHeight(_lastContentWidth);\n        }\n\n        private static object CreateDefaultElementValue(TriProperty property)\n        {\n            var canActivate = property.ArrayElementType.IsValueType ||\n                              property.ArrayElementType.GetConstructor(Type.EmptyTypes) != null;\n\n            return canActivate ? Activator.CreateInstance(property.ArrayElementType) : null;\n        }\n\n        private static Array CloneValue(TriProperty property)\n        {\n            var list = (IList) property.Value;\n            var template = Array.CreateInstance(property.ArrayElementType, list?.Count ?? 0);\n            list?.CopyTo(template, 0);\n            return template;\n        }\n\n        private bool TryGetDragAndDropObject(Object obj, out Object result)\n        {\n            if (obj == null)\n            {\n                result = null;\n                return false;\n            }\n\n            var elementType = _property.ArrayElementType;\n            var objType = obj.GetType();\n\n            if (elementType == objType || elementType.IsAssignableFrom(objType))\n            {\n                result = obj;\n                return true;\n            }\n\n            if (obj is GameObject go && typeof(Component).IsAssignableFrom(elementType) &&\n                go.TryGetComponent(elementType, out var component))\n            {\n                result = component;\n                return true;\n            }\n\n            result = null;\n            return false;\n        }\n\n        private class ListPropertyOverrideContext : TriPropertyOverrideContext\n        {\n            public static readonly ListPropertyOverrideContext Instance = new ListPropertyOverrideContext();\n\n            private readonly GUIContent _noneLabel = GUIContent.none;\n\n            public override bool TryGetDisplayName(TriProperty property, out GUIContent displayName)\n            {\n                var showLabels = property.TryGetAttribute(out ListDrawerSettingsAttribute settings) &&\n                                 settings.ShowElementLabels;\n\n                if (!showLabels)\n                {\n                    displayName = _noneLabel;\n                    return true;\n                }\n\n                displayName = default;\n                return false;\n            }\n        }\n\n        private static class Styles\n        {\n            public static readonly GUIStyle ItemsCount;\n\n            static Styles()\n            {\n                ItemsCount = new GUIStyle(GUI.skin.label)\n                {\n                    alignment = TextAnchor.MiddleRight,\n                    normal =\n                    {\n                        textColor = EditorGUIUtility.isProSkin\n                            ? new Color(0.6f, 0.6f, 0.6f)\n                            : new Color(0.3f, 0.3f, 0.3f),\n                    },\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriListElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c9ed87465ed54b039d11e455c4aa3efc\ntimeCreated: 1638776402"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriMultiEditNotSupportedElement.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriMultiEditNotSupportedElement : TriElement\n    {\n        private readonly TriProperty _property;\n        private readonly GUIContent _message;\n\n        public TriMultiEditNotSupportedElement(TriProperty property)\n        {\n            _property = property;\n            _message = new GUIContent(\"Multi edit not supported\");\n        }\n\n        public override float GetHeight(float width)\n        {\n            return EditorGUIUtility.singleLineHeight;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            EditorGUI.LabelField(position, _property.DisplayNameContent, _message);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriMultiEditNotSupportedElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 575bf0dafd7f459fb09451ec5a83c427\ntimeCreated: 1641382168"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriNoDrawerElement.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriNoDrawerElement : TriElement\n    {\n        private readonly GUIContent _message;\n        private readonly TriProperty _property;\n\n        public TriNoDrawerElement(TriProperty property)\n        {\n            _property = property;\n            _message = new GUIContent($\"No drawer for {property.FieldType}\");\n        }\n\n        public override float GetHeight(float width)\n        {\n            return EditorGUIUtility.singleLineHeight;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            EditorGUI.LabelField(position, _property.DisplayNameContent, _message);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriNoDrawerElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e6cc0cc1449a4af4b8d435b87ef20378\ntimeCreated: 1639319113"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriPropertyCollectionBaseElement.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing JetBrains.Annotations;\nusing VirtueSky.Inspector.Utilities;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public abstract class TriPropertyCollectionBaseElement : TriElement\n    {\n        private List<DeclareGroupBaseAttribute> _declarations = new List<DeclareGroupBaseAttribute>();\n\n        private Dictionary<string, TriPropertyCollectionBaseElement> _groups;\n\n        internal void ClearGroups()\n        {\n            _declarations.Clear();\n        }\n\n        [PublicAPI]\n        public void DeclareGroups([CanBeNull] Type type)\n        {\n            if (type == null)\n            {\n                return;\n            }\n\n            foreach (var attribute in TriReflectionUtilities.GetAttributesCached(type))\n            {\n                if (attribute is DeclareGroupBaseAttribute declareAttribute)\n                {\n                    _declarations.Add(declareAttribute);\n                }\n            }\n        }\n\n        [PublicAPI]\n        public void AddProperty(TriProperty property)\n        {\n            AddProperty(property, default, out _);\n        }\n\n        [PublicAPI]\n        public void AddProperty(TriProperty property, TriPropertyElement.Props props, out string group)\n        {\n            var propertyElement = new TriPropertyElement(property, props);\n\n            if (property.TryGetAttribute(out GroupAttribute groupAttribute))\n            {\n                IEnumerable<string> path = groupAttribute.Path.Split('/');\n\n                var remaining = path.GetEnumerator();\n                if (remaining.MoveNext())\n                {\n                    group = remaining.Current;\n                    AddGroupedChild(propertyElement, property, remaining.Current, remaining.Current, remaining);\n                }\n                else\n                {\n                    group = null;\n                    AddPropertyChild(propertyElement, property);\n                }\n            }\n            else\n            {\n                group = null;\n                AddPropertyChild(propertyElement, property);\n            }\n        }\n\n        private void AddGroupedChild(TriElement child, TriProperty property, string currentPath, string currentName,\n            IEnumerator<string> remainingPath)\n        {\n            if (_groups == null)\n            {\n                _groups = new Dictionary<string, TriPropertyCollectionBaseElement>();\n            }\n\n            var groupElement = CreateSubGroup(property, currentPath, currentName);\n\n            if (remainingPath.MoveNext())\n            {\n                var nextPath = currentPath + \"/\" + remainingPath.Current;\n                var nextName = remainingPath.Current;\n\n                groupElement.AddGroupedChild(child, property, nextPath, nextName, remainingPath);\n            }\n            else\n            {\n                groupElement.AddPropertyChild(child, property);\n            }\n        }\n\n        private TriPropertyCollectionBaseElement CreateSubGroup(TriProperty property,\n            string groupPath, string groupName)\n        {\n            if (!_groups.TryGetValue(groupName, out var groupElement))\n            {\n                var declaration = _declarations.FirstOrDefault(it => it.Path == groupPath);\n\n                if (declaration != null)\n                {\n                    groupElement = TriDrawersUtilities.TryCreateGroupElementFor(declaration);\n                }\n\n                if (groupElement == null)\n                {\n                    groupElement = new DefaultGroupElement();\n                }\n\n                groupElement._declarations = _declarations;\n\n                _groups.Add(groupName, groupElement);\n\n                AddPropertyChild(groupElement, property);\n            }\n\n            return groupElement;\n        }\n\n        protected virtual void AddPropertyChild(TriElement element, TriProperty property)\n        {\n            AddChild(element);\n        }\n\n        private class DefaultGroupElement : TriPropertyCollectionBaseElement\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriPropertyCollectionBaseElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1373b681c88a425c943ea5e6d149a217\ntimeCreated: 1639412705"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriPropertyElement.cs",
    "content": "﻿using System;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriPropertyElement : TriElement\n    {\n        private readonly TriProperty _property;\n\n        [Serializable]\n        public struct Props\n        {\n            public bool forceInline;\n        }\n\n        public TriPropertyElement(TriProperty property, Props props = default)\n        {\n            _property = property;\n\n            foreach (var error in _property.ExtensionErrors)\n            {\n                AddChild(new TriInfoBoxElement(error, TriMessageType.Error));\n            }\n\n            var element = CreateElement(property, props);\n\n            var drawers = property.AllDrawers;\n            for (var index = drawers.Count - 1; index >= 0; index--)\n            {\n                element = drawers[index].CreateElementInternal(property, element);\n            }\n\n            AddChild(element);\n        }\n\n        public override float GetHeight(float width)\n        {\n            if (!_property.IsVisible)\n            {\n                return -EditorGUIUtility.standardVerticalSpacing;\n            }\n\n            return base.GetHeight(width);\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (!_property.IsVisible)\n            {\n                return;\n            }\n\n            var oldShowMixedValue = EditorGUI.showMixedValue;\n            var oldEnabled = GUI.enabled;\n\n            GUI.enabled &= _property.IsEnabled;\n            EditorGUI.showMixedValue = _property.IsValueMixed;\n            var overrideCtx = TriPropertyOverrideContext.BeginProperty();\n\n            if (_property.TryGetSerializedProperty(out var serializedProperty))\n            {\n                EditorGUI.BeginProperty(position, null, serializedProperty);\n            }\n\n            base.OnGUI(position);\n\n            if (_property.TryGetSerializedProperty(out _))\n            {\n                EditorGUI.EndProperty();\n            }\n\n            overrideCtx.EndProperty();\n            EditorGUI.showMixedValue = oldShowMixedValue;\n            GUI.enabled = oldEnabled;\n        }\n\n        private static TriElement CreateElement(TriProperty property, Props props)\n        {\n            switch (property.PropertyType)\n            {\n                case TriPropertyType.Array:\n                {\n                    return CreateArrayElement(property);\n                }\n\n                case TriPropertyType.Reference:\n                {\n                    return CreateReferenceElement(property, props);\n                }\n\n                case TriPropertyType.Generic:\n                {\n                    return CreateGenericElement(property, props);\n                }\n\n                default:\n                {\n                    return new TriNoDrawerElement(property);\n                }\n            }\n        }\n\n        private static TriElement CreateArrayElement(TriProperty property)\n        {\n            return new TriListElement(property);\n        }\n\n        private static TriElement CreateReferenceElement(TriProperty property, Props props)\n        {\n            if (property.TryGetAttribute(out InlinePropertyAttribute inlineAttribute))\n            {\n                return new TriReferenceElement(property, new TriReferenceElement.Props\n                {\n                    inline = true,\n                    drawPrefixLabel = !props.forceInline,\n                    labelWidth = inlineAttribute.LabelWidth,\n                });\n            }\n\n            if (props.forceInline)\n            {\n                return new TriReferenceElement(property, new TriReferenceElement.Props\n                {\n                    inline = true,\n                    drawPrefixLabel = false,\n                });\n            }\n\n            return new TriReferenceElement(property, new TriReferenceElement.Props\n            {\n                inline = false,\n                drawPrefixLabel = false,\n            });\n        }\n\n        private static TriElement CreateGenericElement(TriProperty property, Props props)\n        {\n            if (property.TryGetAttribute(out InlinePropertyAttribute inlineAttribute))\n            {\n                return new TriInlineGenericElement(property, new TriInlineGenericElement.Props\n                {\n                    drawPrefixLabel = !props.forceInline,\n                    labelWidth = inlineAttribute.LabelWidth,\n                });\n            }\n\n            if (props.forceInline)\n            {\n                return new TriInlineGenericElement(property, new TriInlineGenericElement.Props\n                {\n                    drawPrefixLabel = false,\n                });\n            }\n\n            return new TriFoldoutElement(property);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriPropertyElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f57a61ef6fe34b51939950c6b9597f88\ntimeCreated: 1638776439"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriReferenceElement.cs",
    "content": "﻿using System;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    internal class TriReferenceElement : TriPropertyCollectionBaseElement\n    {\n        private readonly Props _props;\n        private readonly TriProperty _property;\n        private readonly bool _showReferencePicker;\n        private readonly bool _skipReferencePickerExtraLine;\n\n        private Type _referenceType;\n\n        [Serializable]\n        public struct Props\n        {\n            public bool inline;\n            public bool drawPrefixLabel;\n            public float labelWidth;\n        }\n\n        public TriReferenceElement(TriProperty property, Props props = default)\n        {\n            _property = property;\n            _props = props;\n            _showReferencePicker = !property.TryGetAttribute(out HideReferencePickerAttribute _);\n            _skipReferencePickerExtraLine = !_showReferencePicker && _props.inline;\n        }\n\n        public override bool Update()\n        {\n            var dirty = false;\n\n            if (_props.inline || _property.IsExpanded)\n            {\n                dirty |= GenerateChildren();\n            }\n            else\n            {\n                dirty |= ClearChildren();\n            }\n\n            dirty |= base.Update();\n\n            return dirty;\n        }\n\n        public override float GetHeight(float width)\n        {\n            var height = _skipReferencePickerExtraLine ? 0f : EditorGUIUtility.singleLineHeight;\n\n            if (_props.inline || _property.IsExpanded)\n            {\n                height += base.GetHeight(width);\n            }\n\n            return height;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (_props.drawPrefixLabel)\n            {\n                var controlId = GUIUtility.GetControlID(FocusType.Passive);\n                position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent);\n            }\n\n            var headerRect = new Rect(position)\n            {\n                height = _skipReferencePickerExtraLine ? 0f : EditorGUIUtility.singleLineHeight,\n            };\n            var headerLabelRect = new Rect(position)\n            {\n                height = headerRect.height,\n                width = EditorGUIUtility.labelWidth,\n            };\n            var headerFieldRect = new Rect(position)\n            {\n                height = headerRect.height,\n                xMin = headerRect.xMin + EditorGUIUtility.labelWidth,\n            };\n            var contentRect = new Rect(position)\n            {\n                yMin = position.yMin + headerRect.height,\n            };\n\n            if (_props.inline)\n            {\n                if (_showReferencePicker)\n                {\n                    TriManagedReferenceGui.DrawTypeSelector(headerRect, _property);\n                }\n\n                using (TriGuiHelper.PushLabelWidth(_props.labelWidth))\n                {\n                    base.OnGUI(contentRect);\n                }\n            }\n            else\n            {\n                TriEditorGUI.Foldout(headerLabelRect, _property);\n\n                if (_showReferencePicker)\n                {\n                    TriManagedReferenceGui.DrawTypeSelector(headerFieldRect, _property);\n                }\n\n                if (_property.IsExpanded)\n                {\n                    using (var indentedRectScope = TriGuiHelper.PushIndentedRect(contentRect, 1))\n                    using (TriGuiHelper.PushLabelWidth(_props.labelWidth))\n                    {\n                        base.OnGUI(indentedRectScope.IndentedRect);\n                    }\n                }\n            }\n        }\n\n        private bool GenerateChildren()\n        {\n            if (_property.ValueType == _referenceType)\n            {\n                return false;\n            }\n\n            _referenceType = _property.ValueType;\n\n            RemoveAllChildren();\n\n            ClearGroups();\n            DeclareGroups(_property.ValueType);\n\n            foreach (var childProperty in _property.ChildrenProperties)\n            {\n                AddProperty(childProperty);\n            }\n\n            return true;\n        }\n\n        private bool ClearChildren()\n        {\n            if (ChildrenCount == 0)\n            {\n                return false;\n            }\n\n            _referenceType = null;\n            RemoveAllChildren();\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriReferenceElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 7dd13898e07a45afacca03cc86c0e24c\ntimeCreated: 1638789498"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriTabGroupElement.cs",
    "content": "﻿using System.Collections.Generic;\nusing VirtueSky.Inspector.Resolvers;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriTabGroupElement : TriHeaderGroupBaseElement\n    {\n        private const string DefaultTabName = \"Main\";\n\n        private readonly List<TabInfo> _tabs;\n        private readonly Dictionary<string, TriElement> _tabElements;\n\n        private string _activeTabName;\n\n        private struct TabInfo\n        {\n            public string name;\n            public ValueResolver<string> titleResolver;\n            public TriProperty property;\n        }\n\n        public TriTabGroupElement()\n        {\n            _tabs = new List<TabInfo>();\n            _tabElements = new Dictionary<string, TriElement>();\n            _activeTabName = null;\n        }\n\n        protected override void DrawHeader(Rect position)\n        {\n            if (_tabs.Count == 0)\n            {\n                return;\n            }\n\n            var tabRect = new Rect(position)\n            {\n                width = position.width / _tabs.Count,\n            };\n\n            if (_tabs.Count == 1)\n            {\n                var tab = _tabs[0];\n                var content = tab.titleResolver.GetValue(tab.property);\n                GUI.Toggle(tabRect, true, content, TriEditorStyles.TabOnlyOne);\n            }\n            else\n            {\n                for (int index = 0, tabCount = _tabs.Count; index < tabCount; index++)\n                {\n                    var tab = _tabs[index];\n                    var content = tab.titleResolver.GetValue(tab.property);\n                    var tabStyle = index == 0 ? TriEditorStyles.TabFirst\n                        : index == tabCount - 1 ? TriEditorStyles.TabLast\n                        : TriEditorStyles.TabMiddle;\n\n                    var isTabActive = GUI.Toggle(tabRect, _activeTabName == tab.name, content, tabStyle);\n                    if (isTabActive && _activeTabName != tab.name)\n                    {\n                        SetActiveTab(tab.name);\n                    }\n\n                    tabRect.x += tabRect.width;\n                }\n            }\n        }\n\n        protected override void AddPropertyChild(TriElement element, TriProperty property)\n        {\n            var tabName = DefaultTabName;\n\n            if (property.TryGetAttribute(out TabAttribute tab))\n            {\n                tabName = tab.TabName ?? tabName;\n            }\n\n            if (!_tabElements.TryGetValue(tabName, out var tabElement))\n            {\n                tabElement = new TriElement();\n\n                var info = new TabInfo\n                {\n                    name = tabName,\n                    titleResolver = ValueResolver.ResolveString(property.Definition, tabName),\n                    property = property,\n                };\n\n                _tabElements[tabName] = tabElement;\n                _tabs.Add(info);\n\n                if (info.titleResolver.TryGetErrorString(out var error))\n                {\n                    tabElement.AddChild(new TriInfoBoxElement(error, TriMessageType.Error));\n                }\n\n                if (_activeTabName == null)\n                {\n                    SetActiveTab(tabName);\n                }\n            }\n\n            tabElement.AddChild(element);\n        }\n\n        private void SetActiveTab(string tabName)\n        {\n            _activeTabName = tabName;\n\n            RemoveAllChildren();\n\n            AddChild(_tabElements[_activeTabName]);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriTabGroupElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: deb5a57d2d0a4476a3e396a49b9f44da\ntimeCreated: 1642759023"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriUiToolkitPropertyElemenet.cs",
    "content": "﻿using VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEditor.UIElements;\nusing UnityEngine;\nusing UnityEngine.UIElements;\n\nnamespace VirtueSky.Inspector.Elements\n{\n    public class TriUiToolkitPropertyElement : TriElement\n    {\n        private readonly SerializedProperty _serializedProperty;\n\n        private readonly VisualElement _rootElement;\n        private readonly VisualElement _selfElement;\n\n        private bool _heightDirty;\n\n        public TriUiToolkitPropertyElement(\n            TriProperty property,\n            SerializedProperty serializedProperty,\n            VisualElement selfElement,\n            VisualElement rootElement)\n        {\n            _serializedProperty = serializedProperty;\n            _selfElement = selfElement;\n            _rootElement = rootElement;\n\n            _selfElement.style.position = Position.Absolute;\n        }\n\n        protected override void OnAttachToPanel()\n        {\n            base.OnAttachToPanel();\n\n            _rootElement.schedule.Execute(() =>\n            {\n                _rootElement.Add(_selfElement);\n                _selfElement.Bind(_serializedProperty.serializedObject);\n            });\n        }\n\n        protected override void OnDetachFromPanel()\n        {\n            _rootElement.schedule.Execute(() =>\n            {\n                _selfElement.Unbind();\n                _rootElement.Remove(_selfElement);\n            });\n\n            base.OnDetachFromPanel();\n        }\n\n        public override bool Update()\n        {\n            var dirty = base.Update();\n\n            if (_heightDirty)\n            {\n                _heightDirty = false;\n                dirty = true;\n            }\n\n            return dirty;\n        }\n\n        public override float GetHeight(float width)\n        {\n            var height = _selfElement.resolvedStyle.height;\n\n            if (float.IsNaN(height))\n            {\n                _heightDirty = true;\n                return 0f;\n            }\n\n            return height;\n        }\n\n        public override void OnGUI(Rect position)\n        {\n            if (Event.current.type == EventType.Repaint)\n            {\n                var pos = GUIClipProxy.UnClip(position.position);\n\n                _selfElement.style.width = position.width;\n                _selfElement.style.left = pos.x;\n                _selfElement.style.top = pos.y;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriUiToolkitPropertyElemenet.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 535ce5f65f424a8c9e83943eda845fc6\ntimeCreated: 1690621289"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriVerticalGroupElement.cs",
    "content": "﻿namespace VirtueSky.Inspector.Elements\n{\n    public class TriVerticalGroupElement : TriPropertyCollectionBaseElement\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements/TriVerticalGroupElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ec0e2c38af6f4830b3eca87e63c3248c\ntimeCreated: 1643558785"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Elements.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 99d0fe2f9d1c4cb88cf46ba5813c091f\ntimeCreated: 1638772919"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ActionResolver.cs",
    "content": "﻿using JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    public abstract class ActionResolver\n    {\n        public static ActionResolver Resolve(TriPropertyDefinition propertyDefinition, string method)\n        {\n            if (InstanceActionResolver.TryResolve(propertyDefinition, method, out var iar))\n            {\n                return iar;\n            }\n\n            return new ErrorActionResolver(propertyDefinition, method);\n        }\n\n        [PublicAPI]\n        public abstract bool TryGetErrorString(out string error);\n\n        [PublicAPI]\n        public abstract void InvokeForTarget(TriProperty property, int targetIndex);\n\n        [PublicAPI]\n        public void InvokeForAllTargets(TriProperty property)\n        {\n            for (var targetIndex = 0; targetIndex < property.PropertyTree.TargetsCount; targetIndex++)\n            {\n                InvokeForTarget(property, targetIndex);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ActionResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 188152364708438db80df00df894ae87\ntimeCreated: 1652265564"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/DropdownValuesResolver.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    public class DropdownValuesResolver<T>\n    {\n        [CanBeNull] private ValueResolver<IEnumerable<TriDropdownItem<T>>> _itemsResolver;\n        [CanBeNull] private ValueResolver<IEnumerable<T>> _valuesResolver;\n\n        [PublicAPI]\n        public static DropdownValuesResolver<T> Resolve(TriPropertyDefinition propertyDefinition, string expression)\n        {\n            var valuesResolver = ValueResolver.Resolve<IEnumerable<T>>(propertyDefinition, expression);\n            if (!valuesResolver.TryGetErrorString(out _))\n            {\n                return new DropdownValuesResolver<T>\n                {\n                    _valuesResolver = valuesResolver,\n                };\n            }\n\n            var itemsResolver = ValueResolver.Resolve<IEnumerable<TriDropdownItem<T>>>(propertyDefinition, expression);\n\n            return new DropdownValuesResolver<T>\n            {\n                _itemsResolver = itemsResolver,\n            };\n        }\n\n        [PublicAPI]\n        public bool TryGetErrorString(out string error)\n        {\n            return ValueResolver.TryGetErrorString(_valuesResolver, _itemsResolver, out error);\n        }\n\n        [PublicAPI]\n        public IEnumerable<ITriDropdownItem> GetDropdownItems(TriProperty property)\n        {\n            if (_valuesResolver != null)\n            {\n                var values = _valuesResolver.GetValue(property, Enumerable.Empty<T>());\n\n                foreach (var value in values)\n                {\n                    yield return new TriDropdownItem {Text = $\"{value}\", Value = value,};\n                }\n            }\n\n            if (_itemsResolver != null)\n            {\n                var values = _itemsResolver.GetValue(property, Enumerable.Empty<TriDropdownItem<T>>());\n\n                foreach (var value in values)\n                {\n                    yield return value;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/DropdownValuesResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 16fa8c4711a44bdea6facb3bc68822d9\ntimeCreated: 1680713564"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ErrorActionResolver.cs",
    "content": "﻿using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    internal sealed class ErrorActionResolver : ActionResolver\n    {\n        private readonly string _method;\n\n        public ErrorActionResolver(TriPropertyDefinition propertyDefinition, string method)\n        {\n            _method = method;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = $\"Method '{_method}' not exists or has wrong signature\";\n            return true;\n        }\n\n        public override void InvokeForTarget(TriProperty property, int targetIndex)\n        {\n            Debug.LogException(new InvalidOperationException(\"Method not exists\"));\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ErrorActionResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 52fddb0e965c4a8e82a2956d2f6ba53b\ntimeCreated: 1652265995"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ErrorValueResolver.cs",
    "content": "﻿namespace VirtueSky.Inspector.Resolvers\n{\n    internal class ErrorValueResolver<T> : ValueResolver<T>\n    {\n        private readonly string _expression;\n\n        public ErrorValueResolver(TriPropertyDefinition propertyDefinition, string expression)\n        {\n            _expression = expression;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = $\"Method '{_expression}' not exists or has wrong signature\";\n            return true;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            return defaultValue;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ErrorValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: b3b804d7029c42c0b5f5a692281dacbf\ntimeCreated: 1652096547"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstanceActionResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    internal sealed class InstanceActionResolver : ActionResolver\n    {\n        private readonly MethodInfo _methodInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string method,\n            out ActionResolver resolver)\n        {\n            var parentType = propertyDefinition.OwnerType;\n            if (parentType == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var methodInfo in parentType.GetMethods(flags))\n            {\n                if (methodInfo.Name == method &&\n                    methodInfo.ReturnType == typeof(void) &&\n                    methodInfo.GetParameters() is var parameterInfos &&\n                    parameterInfos.Length == 0)\n                {\n                    resolver = new InstanceActionResolver(methodInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        private InstanceActionResolver(MethodInfo methodInfo)\n        {\n            _methodInfo = methodInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override void InvokeForTarget(TriProperty property, int targetIndex)\n        {\n            var parentValue = property.Owner.GetValue(targetIndex);\n\n            try\n            {\n                _methodInfo.Invoke(parentValue, Array.Empty<object>());\n            }\n            catch (Exception e)\n            {\n                Debug.LogException(e);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstanceActionResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 737737f290e8433e9f160970cf996e4c\ntimeCreated: 1652266150"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstanceFieldValueResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    internal sealed class InstanceFieldValueResolver<T> : ValueResolver<T>\n    {\n        private readonly FieldInfo _fieldInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression,\n            out ValueResolver<T> resolver)\n        {\n            var parentType = propertyDefinition.OwnerType;\n            if (parentType == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var fieldInfo in parentType.GetFields(flags))\n            {\n                if (fieldInfo.Name == expression &&\n                    typeof(T).IsAssignableFrom(fieldInfo.FieldType))\n                {\n                    resolver = new InstanceFieldValueResolver<T>(fieldInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        private InstanceFieldValueResolver(FieldInfo fieldInfo)\n        {\n            _fieldInfo = fieldInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            var parentValue = property.Owner.GetValue(0);\n\n            try\n            {\n                return (T) _fieldInfo.GetValue(parentValue);\n            }\n            catch (Exception e)\n            {\n                if (e is TargetInvocationException targetInvocationException)\n                {\n                    e = targetInvocationException.InnerException;\n                }\n\n                Debug.LogException(e);\n                return defaultValue;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstanceFieldValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1c19d3705b8f4c9caf951d60efa47acf\ntimeCreated: 1652287302"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstanceMethodValueResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    internal sealed class InstanceMethodValueResolver<T> : ValueResolver<T>\n    {\n        private readonly MethodInfo _methodInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression,\n            out ValueResolver<T> resolver)\n        {\n            var parentType = propertyDefinition.OwnerType;\n            if (parentType == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var methodInfo in parentType.GetMethods(flags))\n            {\n                if (methodInfo.Name == expression &&\n                    typeof(T).IsAssignableFrom(methodInfo.ReturnType) &&\n                    methodInfo.GetParameters() is var parameterInfos &&\n                    parameterInfos.Length == 0)\n                {\n                    resolver = new InstanceMethodValueResolver<T>(methodInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        private InstanceMethodValueResolver(MethodInfo methodInfo)\n        {\n            _methodInfo = methodInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            var parentValue = property.Owner.GetValue(0);\n\n            try\n            {\n                return (T) _methodInfo.Invoke(parentValue, Array.Empty<object>());\n            }\n            catch (Exception e)\n            {\n                if (e is TargetInvocationException targetInvocationException)\n                {\n                    e = targetInvocationException.InnerException;\n                }\n\n                Debug.LogException(e);\n                return defaultValue;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstanceMethodValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: cee79123a0e84d5d9795ea92ed1b6d9e\ntimeCreated: 1652097174"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstancePropertyValueResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    internal sealed class InstancePropertyValueResolver<T> : ValueResolver<T>\n    {\n        private readonly PropertyInfo _propertyInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression,\n            out ValueResolver<T> resolver)\n        {\n            var parentType = propertyDefinition.OwnerType;\n            if (parentType == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var propertyInfo in parentType.GetProperties(flags))\n            {\n                if (propertyInfo.Name == expression &&\n                    typeof(T).IsAssignableFrom(propertyInfo.PropertyType) &&\n                    propertyInfo.CanRead)\n                {\n                    resolver = new InstancePropertyValueResolver<T>(propertyInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        private InstancePropertyValueResolver(PropertyInfo propertyInfo)\n        {\n            _propertyInfo = propertyInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            var parentValue = property.Owner.GetValue(0);\n\n            try\n            {\n                return (T) _propertyInfo.GetValue(parentValue);\n            }\n            catch (Exception e)\n            {\n                if (e is TargetInvocationException targetInvocationException)\n                {\n                    e = targetInvocationException.InnerException;\n                }\n\n                Debug.LogException(e);\n                return defaultValue;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/InstancePropertyValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 53c22267d5cf488c86afabea3d4613b0\ntimeCreated: 1652287280"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/StaticFieldValueResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    public class StaticFieldValueResolver<T> : ValueResolver<T>\n    {\n        private readonly FieldInfo _fieldInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression,\n            out ValueResolver<T> resolver)\n        {\n            var type = propertyDefinition.OwnerType;\n            var fieldName = expression;\n\n            var separatorIndex = expression.LastIndexOf('.');\n            if (separatorIndex >= 0)\n            {\n                var className = expression.Substring(0, separatorIndex);\n                fieldName = expression.Substring(separatorIndex + 1);\n\n                if (!TriReflectionUtilities.TryFindTypeByFullName(className, out type))\n                {\n                    resolver = null;\n                    return false;\n                }\n            }\n\n            if (type == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var fieldInfo in type.GetFields(flags))\n            {\n                if (fieldInfo.Name == fieldName &&\n                    typeof(T).IsAssignableFrom(fieldInfo.FieldType))\n                {\n                    resolver = new StaticFieldValueResolver<T>(fieldInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        public StaticFieldValueResolver(FieldInfo fieldInfo)\n        {\n            _fieldInfo = fieldInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            try\n            {\n                return (T) _fieldInfo.GetValue(null);\n            }\n            catch (Exception e)\n            {\n                if (e is TargetInvocationException targetInvocationException)\n                {\n                    e = targetInvocationException.InnerException;\n                }\n\n                Debug.LogException(e);\n                return defaultValue;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/StaticFieldValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: bc82b93a5bf949958553418b396127ec\ntimeCreated: 1657955836"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/StaticMethodValueResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    public class StaticMethodValueResolver<T> : ValueResolver<T>\n    {\n        private readonly MethodInfo _methodInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression,\n            out ValueResolver<T> resolver)\n        {\n            var type = propertyDefinition.OwnerType;\n            var methodName = expression;\n            \n            var separatorIndex = expression.LastIndexOf('.');\n            if (separatorIndex >= 0)\n            {\n                var className = expression.Substring(0, separatorIndex);\n                methodName = expression.Substring(separatorIndex + 1);\n\n                if (!TriReflectionUtilities.TryFindTypeByFullName(className, out type))\n                {\n                    resolver = null;\n                    return false;\n                }\n            }\n\n            if (type == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var methodInfo in type.GetMethods(flags))\n            {\n                if (methodInfo.Name == methodName &&\n                    typeof(T).IsAssignableFrom(methodInfo.ReturnType) &&\n                    methodInfo.GetParameters() is var parametersInfo &&\n                    parametersInfo.Length == 0)\n                {\n                    resolver = new StaticMethodValueResolver<T>(methodInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        public StaticMethodValueResolver(MethodInfo methodInfo)\n        {\n            _methodInfo = methodInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            try\n            {\n                return (T) _methodInfo.Invoke(null, null);\n            }\n            catch (Exception e)\n            {\n                if (e is TargetInvocationException targetInvocationException)\n                {\n                    e = targetInvocationException.InnerException;\n                }\n\n                Debug.LogException(e);\n                return defaultValue;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/StaticMethodValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 96c731e2cdce45da8ee4be44ce6674ea\ntimeCreated: 1657954360"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/StaticPropertyValueResolver.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    public class StaticPropertyValueResolver<T> : ValueResolver<T>\n    {\n        private readonly PropertyInfo _propertyInfo;\n\n        public static bool TryResolve(TriPropertyDefinition propertyDefinition, string expression,\n            out ValueResolver<T> resolver)\n        {\n            var type = propertyDefinition.OwnerType;\n            var propertyName = expression;\n            \n            var separatorIndex = expression.LastIndexOf('.');\n            if (separatorIndex >= 0)\n            {\n                var className = expression.Substring(0, separatorIndex);\n                propertyName = expression.Substring(separatorIndex + 1);\n\n                if (!TriReflectionUtilities.TryFindTypeByFullName(className, out type))\n                {\n                    resolver = null;\n                    return false;\n                }\n            }\n\n            if (type == null)\n            {\n                resolver = null;\n                return false;\n            }\n\n            const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;\n\n            foreach (var propertyInfo in type.GetProperties(flags))\n            {\n                if (propertyInfo.Name == propertyName &&\n                    typeof(T).IsAssignableFrom(propertyInfo.PropertyType) &&\n                    propertyInfo.CanRead)\n                {\n                    resolver = new StaticPropertyValueResolver<T>(propertyInfo);\n                    return true;\n                }\n            }\n\n            resolver = null;\n            return false;\n        }\n\n        public StaticPropertyValueResolver(PropertyInfo propertyInfo)\n        {\n            _propertyInfo = propertyInfo;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = \"\";\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            try\n            {\n                return (T) _propertyInfo.GetValue(null);\n            }\n            catch (Exception e)\n            {\n                if (e is TargetInvocationException targetInvocationException)\n                {\n                    e = targetInvocationException.InnerException;\n                }\n\n                Debug.LogException(e);\n                return defaultValue;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/StaticPropertyValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 8cbab37d02e54764a8b1ae73eac12d8a\ntimeCreated: 1657955361"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ValueResolver.cs",
    "content": "﻿using JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector.Resolvers\n{\n    public static class ValueResolver\n    {\n        public static ValueResolver<T> Resolve<T>(TriPropertyDefinition propertyDefinition,\n            string expression)\n        {\n            if (expression != null && expression.StartsWith(\"$\"))\n            {\n                expression = expression.Substring(1);\n            }\n\n            if (StaticFieldValueResolver<T>.TryResolve(propertyDefinition, expression, out var sfr))\n            {\n                return sfr;\n            }\n\n            if (StaticPropertyValueResolver<T>.TryResolve(propertyDefinition, expression, out var spr))\n            {\n                return spr;\n            }\n\n            if (StaticMethodValueResolver<T>.TryResolve(propertyDefinition, expression, out var smr))\n            {\n                return smr;\n            }\n\n            if (InstanceFieldValueResolver<T>.TryResolve(propertyDefinition, expression, out var ifr))\n            {\n                return ifr;\n            }\n\n            if (InstancePropertyValueResolver<T>.TryResolve(propertyDefinition, expression, out var ipr))\n            {\n                return ipr;\n            }\n\n            if (InstanceMethodValueResolver<T>.TryResolve(propertyDefinition, expression, out var imr))\n            {\n                return imr;\n            }\n\n            return new ErrorValueResolver<T>(propertyDefinition, expression);\n        }\n\n        public static ValueResolver<string> ResolveString(TriPropertyDefinition propertyDefinition,\n            string expression)\n        {\n            if (expression != null && expression.StartsWith(\"$\"))\n            {\n                return Resolve<string>(propertyDefinition, expression.Substring(1));\n            }\n\n            return new ConstantValueResolver<string>(expression);\n        }\n\n        public static bool TryGetErrorString<T>([CanBeNull] ValueResolver<T> resolver, out string error)\n        {\n            return TryGetErrorString<T, T>(resolver, null, out error);\n        }\n\n        public static bool TryGetErrorString<T1, T2>(ValueResolver<T1> resolver1, ValueResolver<T2> resolver2,\n            out string error)\n        {\n            if (resolver1 != null && resolver1.TryGetErrorString(out var error1))\n            {\n                error = error1;\n                return true;\n            }\n\n            if (resolver2 != null && resolver2.TryGetErrorString(out var error2))\n            {\n                error = error2;\n                return true;\n            }\n\n            error = null;\n            return false;\n        }\n    }\n\n    public abstract class ValueResolver<T>\n    {\n        [PublicAPI]\n        public abstract bool TryGetErrorString(out string error);\n\n        [PublicAPI]\n        public abstract T GetValue(TriProperty property, T defaultValue = default);\n    }\n\n    public sealed class ConstantValueResolver<T> : ValueResolver<T>\n    {\n        private readonly T _value;\n\n        public ConstantValueResolver(T value)\n        {\n            _value = value;\n        }\n\n        public override bool TryGetErrorString(out string error)\n        {\n            error = default;\n            return false;\n        }\n\n        public override T GetValue(TriProperty property, T defaultValue = default)\n        {\n            return _value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers/ValueResolver.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 467299addfb7498fbb7e7f0e449c4364\ntimeCreated: 1652095635"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resolvers.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ca8a2709dde94e318cb5cfdc801d9045\ntimeCreated: 1652095622"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resources/TriInspector_Box_Bg.png.meta",
    "content": "fileFormatVersion: 2\nguid: 7a524300faaf5aa40a2ff59c25b28b71\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 11\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 1\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 0\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 8\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: 5e97eb03825dee720800000000000000\n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n  spritePackingTag: \n  pSDRemoveMatte: 0\n  pSDShowRemoveMatteOption: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resources/TriInspector_Box_Bg_Dark.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6c3f6c6cd431e8e4e87094572f59d524\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 11\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 1\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 0\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 8\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: 5e97eb03825dee720800000000000000\n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n  spritePackingTag: \n  pSDRemoveMatte: 0\n  pSDShowRemoveMatteOption: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resources/TriInspector_Content_Bg.png.meta",
    "content": "fileFormatVersion: 2\nguid: 372e4831c9374244aafdd096c36bb645\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 11\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 1\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 0\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 8\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: 5e97eb03825dee720800000000000000\n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n  spritePackingTag: \n  pSDRemoveMatte: 0\n  pSDShowRemoveMatteOption: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resources/TriInspector_Content_Bg_Dark.png.meta",
    "content": "fileFormatVersion: 2\nguid: d73be6aba60ae5b41887b4116facc353\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 11\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 1\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 0\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 8\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 3\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: 5e97eb03825dee720800000000000000\n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n  spritePackingTag: \n  pSDRemoveMatte: 0\n  pSDShowRemoveMatteOption: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Resources.meta",
    "content": "fileFormatVersion: 2\nguid: d8d4d0876dcc071428509b59e2f78e29\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriAttributeDrawer.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriAttributeDrawer : TriCustomDrawer\n    {\n        internal Attribute RawAttribute { get; set; }\n    }\n\n    public abstract class TriAttributeDrawer<TAttribute> : TriAttributeDrawer\n        where TAttribute : Attribute\n    {\n        [PublicAPI]\n        public TAttribute Attribute => (TAttribute) RawAttribute;\n\n        public sealed override TriElement CreateElementInternal(TriProperty property, TriElement next)\n        {\n            return CreateElement(property, next);\n        }\n\n        [PublicAPI]\n        public virtual TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new DefaultAttributeDrawerElement(this, property, next);\n        }\n\n        [PublicAPI]\n        public virtual float GetHeight(float width, TriProperty property, TriElement next)\n        {\n            return next.GetHeight(width);\n        }\n\n        [PublicAPI]\n        public virtual void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            next.OnGUI(position);\n        }\n\n        internal class DefaultAttributeDrawerElement : TriElement\n        {\n            private readonly TriAttributeDrawer<TAttribute> _drawer;\n            private readonly TriElement _next;\n            private readonly TriProperty _property;\n\n            public DefaultAttributeDrawerElement(TriAttributeDrawer<TAttribute> drawer, TriProperty property,\n                TriElement next)\n            {\n                _drawer = drawer;\n                _property = property;\n                _next = next;\n\n                AddChild(next);\n            }\n\n            public override float GetHeight(float width)\n            {\n                return _drawer.GetHeight(width, _property, _next);\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                _drawer.OnGUI(position, _property, _next);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriAttributeDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 31f59a1db97a4d389263665aaf9bccf1\ntimeCreated: 1639381350"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriCustomDrawer.cs",
    "content": "﻿namespace VirtueSky.Inspector\n{\n    public abstract class TriCustomDrawer : TriPropertyExtension\n    {\n        internal int Order { get; set; }\n\n        public abstract TriElement CreateElementInternal(TriProperty property, TriElement next);\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriCustomDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 896bcecdfc7048de8375841799d14ecc\ntimeCreated: 1638885450"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriDrawerOrder.cs",
    "content": "﻿namespace VirtueSky.Inspector\n{\n    public static class TriDrawerOrder\n    {\n        public const int System = -9999;\n        public const int Inspector = -2000;\n        public const int Validator = -1500;\n        public const int Decorator = -1000;\n        public const int Drawer = 0;\n        public const int Fallback = 9999;\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriDrawerOrder.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 2db5b837fe8643de8e5be9eaee10f509\ntimeCreated: 1639384181"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriEditorStyles.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public static class TriEditorStyles\n    {\n        private static GUIStyle _contentBox;\n        private static GUIStyle _box;\n        \n        public static GUIStyle TabOnlyOne { get; } = \"Tab onlyOne\";\n        public static GUIStyle TabFirst { get; } = \"Tab first\";\n        public static GUIStyle TabMiddle { get; } = \"Tab middle\";\n        public static GUIStyle TabLast { get; } = \"Tab last\";\n        \n        private static GUIStyle FallbackContentBox { get; } = \"HelpBox\";\n        private static GUIStyle FallbackBox { get; } = \"HelpBox\";\n        \n        public static GUIStyle ContentBox\n        {\n            get\n            {\n                if (_contentBox == null)\n                {\n                    var backgroundTexture = LoadTexture(\"TriInspector_Content_Bg\");\n\n                    if (backgroundTexture == null)\n                    {\n                        _contentBox = new GUIStyle(FallbackContentBox);\n                    }\n                    else\n                    {\n                        _contentBox = new GUIStyle\n                        {\n                            normal =\n                            {\n                                background = backgroundTexture,\n                            },\n                        };\n                    }\n\n                    _contentBox.border = new RectOffset(2, 2, 2, 2);\n                }\n\n                return _contentBox;\n            }\n        }\n\n        public static GUIStyle Box\n        {\n            get\n            {\n                if (_box == null)\n                {\n                    var backgroundTexture = LoadTexture(\"TriInspector_Box_Bg\");\n\n                    if (backgroundTexture == null)\n                    {\n                        _box = new GUIStyle(FallbackBox);\n                    }\n                    else\n                    {\n                        _box = new GUIStyle\n                        {\n                            normal =\n                            {\n                                background = backgroundTexture,\n                            },\n                        };\n                    }\n                    \n                    _box.border = new RectOffset(2, 2, 2, 2);\n                }\n\n                return _box;\n            }\n        }\n\n        private static Texture2D LoadTexture(string name)\n        {\n            name = EditorGUIUtility.isProSkin ? $\"{name}_Dark\" : name;\n            \n            var results = AssetDatabase.FindAssets($\"{name} t:texture2D\");\n            \n            if (results.Length == 0) return null;\n            \n            var path = AssetDatabase.GUIDToAssetPath(results[0]);\n            \n            return (Texture2D) EditorGUIUtility.Load(path);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriEditorStyles.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 6f23eb6fd2f644a0a718543287192636\ntimeCreated: 1639462144"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriElement.cs",
    "content": "﻿using System.Collections.Generic;\nusing JetBrains.Annotations;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public class TriElement\n    {\n        private static readonly List<TriElement> Empty = new List<TriElement>();\n\n        private float _cachedHeight;\n        private bool _cachedheightDirty;\n        private bool _attached;\n        private List<TriElement> _children = Empty;\n\n        [PublicAPI]\n        public int ChildrenCount => _children.Count;\n\n        public bool IsAttached => _attached;\n\n        internal float CachedHeight => _cachedHeight;\n\n        [PublicAPI]\n        public virtual bool Update()\n        {\n            if (!_attached)\n            {\n                Debug.LogError($\"{GetType().Name} not attached\");\n            }\n\n            var dirty = false;\n\n            foreach (var child in _children)\n            {\n                dirty |= child.Update();\n            }\n\n            return dirty;\n        }\n\n        [PublicAPI]\n        public virtual float GetHeight(float width)\n        {\n            if (!_attached)\n            {\n                Debug.LogError($\"{GetType().Name} not attached\");\n            }\n\n            if (Event.current.type != EventType.Layout && !_cachedheightDirty)\n            {\n                return _cachedHeight;\n            }\n\n            _cachedheightDirty = false;\n\n            switch (_children.Count)\n            {\n                case 0:\n                    return _cachedHeight = 0f;\n\n                case 1:\n                    return _cachedHeight = _children[0].GetHeight(width);\n\n                default:\n                {\n                    _cachedHeight = (_children.Count - 1) * EditorGUIUtility.standardVerticalSpacing;\n\n                    foreach (var child in _children)\n                    {\n                        _cachedHeight += child.GetHeight(width);\n                    }\n\n                    return _cachedHeight;\n                }\n            }\n        }\n\n        [PublicAPI]\n        public virtual void OnGUI(Rect position)\n        {\n            if (!_attached)\n            {\n                Debug.LogError($\"{GetType().Name} not attached\");\n            }\n\n            switch (_children.Count)\n            {\n                case 0:\n                    break;\n\n                case 1:\n                    _children[0].OnGUI(position);\n                    break;\n\n                default:\n                {\n                    var offset = 0f;\n                    var spacing = EditorGUIUtility.standardVerticalSpacing;\n\n                    foreach (var child in _children)\n                    {\n                        var childHeight = child.GetHeight(position.width);\n\n                        child.OnGUI(new Rect(position.x, position.y + offset, position.width, childHeight));\n\n                        offset += childHeight + spacing;\n                    }\n\n                    break;\n                }\n            }\n        }\n\n        [PublicAPI]\n        public TriElement GetChild(int index)\n        {\n            return _children[index];\n        }\n\n        [PublicAPI]\n        public void RemoveChildAt(int index)\n        {\n            if (_children.Count < index)\n            {\n                return;\n            }\n\n            var child = _children[index];\n            _children.RemoveAt(index);\n            _cachedheightDirty = true;\n\n            if (_attached)\n            {\n                child.DetachInternal();\n            }\n        }\n\n        [PublicAPI]\n        public void RemoveAllChildren()\n        {\n            if (_attached)\n            {\n                foreach (var child in _children)\n                {\n                    child.DetachInternal();\n                }\n            }\n\n            _children.Clear();\n            _cachedheightDirty = true;\n        }\n\n        [PublicAPI]\n        public void AddChild(TriElement child)\n        {\n            if (_children == Empty)\n            {\n                _children = new List<TriElement>();\n            }\n\n            _children.Add(child);\n            _cachedheightDirty = true;\n\n            if (_attached)\n            {\n                child.AttachInternal();\n                child.Update();\n            }\n        }\n\n        internal void AttachInternal()\n        {\n            if (_attached)\n            {\n                Debug.LogError($\"{GetType().Name} already attached\");\n            }\n\n            _attached = true;\n\n            OnAttachToPanel();\n\n            foreach (var child in _children)\n            {\n                child.AttachInternal();\n                child.Update();\n            }\n        }\n\n        internal void DetachInternal()\n        {\n            if (!_attached)\n            {\n                Debug.LogError($\"{GetType().Name} not attached\");\n            }\n\n            _attached = false;\n\n            foreach (var child in _children)\n            {\n                child.DetachInternal();\n            }\n\n            OnDetachFromPanel();\n        }\n\n        protected virtual void OnAttachToPanel()\n        {\n        }\n\n        protected virtual void OnDetachFromPanel()\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriElement.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 543813bc0e9e4045904a35ef56ea6abe\ntimeCreated: 1638771508"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriGroupDrawer.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing VirtueSky.Inspector.Elements;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriGroupDrawer\n    {\n        public abstract TriPropertyCollectionBaseElement CreateElementInternal(Attribute attribute);\n    }\n\n    public abstract class TriGroupDrawer<TAttribute> : TriGroupDrawer\n        where TAttribute : Attribute\n    {\n        public sealed override TriPropertyCollectionBaseElement CreateElementInternal(Attribute attribute)\n        {\n            return CreateElement((TAttribute) attribute);\n        }\n\n        [PublicAPI]\n        public abstract TriPropertyCollectionBaseElement CreateElement(TAttribute attribute);\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c7337ea7305e4a5681ff404a041dc93e\ntimeCreated: 1639417787"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriProperty.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing JetBrains.Annotations;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public sealed class TriProperty\n    {\n        private static readonly StringBuilder SharedPropertyPathStringBuilder = new StringBuilder();\n\n        private static readonly IReadOnlyList<TriValidationResult> EmptyValidationResults =\n            new List<TriValidationResult>();\n\n        private readonly TriPropertyDefinition _definition;\n        private readonly int _propertyIndex;\n        [CanBeNull] private readonly SerializedObject _serializedObject;\n        [CanBeNull] private readonly SerializedProperty _serializedProperty;\n        private List<TriProperty> _childrenProperties;\n        private List<TriValidationResult> _validationResults;\n\n        private GUIContent _displayNameBackingField;\n        private string _propertyPath;\n        private string _isExpandedPrefsKey;\n\n        private int _lastUpdateFrame;\n        private bool _isUpdating;\n\n        [CanBeNull] private object _value;\n        [CanBeNull] private Type _valueType;\n        private bool _isValueMixed;\n\n        public event Action<TriProperty> ValueChanged;\n        public event Action<TriProperty> ChildValueChanged;\n\n        public TriProperty(\n            TriPropertyTree propertyTree,\n            TriProperty parent,\n            TriPropertyDefinition definition,\n            SerializedObject serializedObject\n        )\n        {\n            Parent = parent;\n            _definition = definition;\n            _propertyIndex = -1;\n            _serializedProperty = null;\n            _serializedObject = serializedObject;\n\n            PropertyTree = propertyTree;\n            PropertyType = GetPropertyType(this);\n        }\n\n        public TriProperty(\n            TriPropertyTree propertyTree,\n            TriProperty parent,\n            TriPropertyDefinition definition,\n            int propertyIndex,\n            [CanBeNull] SerializedProperty serializedProperty)\n        {\n            Parent = parent;\n            _definition = definition;\n            _propertyIndex = propertyIndex;\n            _serializedProperty = serializedProperty?.Copy();\n            _serializedObject = _serializedProperty?.serializedObject;\n\n            PropertyTree = propertyTree;\n            PropertyType = GetPropertyType(this);\n        }\n\n        internal TriPropertyDefinition Definition => _definition;\n\n        [PublicAPI] public TriPropertyType PropertyType { get; }\n\n        [PublicAPI] public TriPropertyTree PropertyTree { get; }\n\n        [PublicAPI] public TriProperty Parent { get; }\n\n        [PublicAPI] public TriProperty Owner => IsArrayElement ? Parent.Owner : Parent;\n\n        [PublicAPI] public bool IsRootProperty => Parent == null;\n\n        [PublicAPI] public string RawName => _definition.Name;\n\n        [PublicAPI] public string DisplayName => DisplayNameContent.text;\n\n        public IEqualityComparer Comparer => TriEqualityComparer.Of(ValueType);\n\n        [PublicAPI]\n        public GUIContent DisplayNameContent\n        {\n            get\n            {\n                if (TriPropertyOverrideContext.Current != null &&\n                    TriPropertyOverrideContext.Current.TryGetDisplayName(this, out var overrideName))\n                {\n                    return overrideName;\n                }\n\n                if (_displayNameBackingField == null)\n                {\n                    if (TryGetAttribute(out HideLabelAttribute _) || IsArrayElement)\n                    {\n                        _displayNameBackingField = new GUIContent(\"\");\n                    }\n                    else\n                    {\n                        _displayNameBackingField = new GUIContent(ObjectNames.NicifyVariableName(_definition.Name));\n                    }\n                }\n\n                if (IsArrayElement)\n                {\n                    if (TriUnityInspectorUtilities.TryGetSpecialArrayElementName(this, out var specialName))\n                    {\n                        _displayNameBackingField.text = specialName;\n                    }\n                    else\n                    {\n                        _displayNameBackingField.text = TriUnityInspectorUtilities.GetStandardArrayElementName(this);\n                    }\n                }\n                else\n                {\n                    if (_definition.CustomLabel != null)\n                    {\n                        _displayNameBackingField.text = _definition.CustomLabel.GetValue(this, \"\");\n                    }\n\n                    if (_definition.CustomTooltip != null)\n                    {\n                        _displayNameBackingField.tooltip = _definition.CustomTooltip.GetValue(this, \"\");\n                    }\n                }\n\n                return _displayNameBackingField;\n            }\n        }\n\n        [PublicAPI]\n        public string PropertyPath\n        {\n            get\n            {\n                if (_propertyPath == null)\n                {\n                    SharedPropertyPathStringBuilder.Clear();\n                    BuildPropertyPath(this, SharedPropertyPathStringBuilder);\n                    _propertyPath = SharedPropertyPathStringBuilder.ToString();\n                }\n\n                return _propertyPath;\n            }\n        }\n\n        [PublicAPI]\n        public bool IsVisible\n        {\n            get\n            {\n                foreach (var processor in _definition.HideProcessors)\n                {\n                    if (processor.IsHidden(this))\n                    {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n        }\n\n        [PublicAPI]\n        public bool IsEnabled\n        {\n            get\n            {\n                if (_definition.IsReadOnly)\n                {\n                    return false;\n                }\n\n                foreach (var processor in _definition.DisableProcessors)\n                {\n                    if (processor.IsDisabled(this))\n                    {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n        }\n\n        [PublicAPI] public Type FieldType => _definition.FieldType;\n\n        [PublicAPI] public Type ArrayElementType => _definition.ArrayElementType;\n\n        [PublicAPI] public bool IsArrayElement => _definition.IsArrayElement;\n\n        [PublicAPI] public bool IsArray => _definition.IsArray;\n\n        public int IndexInArray => IsArrayElement\n            ? _propertyIndex\n            : throw new InvalidOperationException(\"Cannot read IndexInArray for !IsArrayElement\");\n\n        public IReadOnlyList<TriCustomDrawer> AllDrawers => _definition.Drawers;\n\n        internal IReadOnlyList<string> ExtensionErrors => _definition.ExtensionErrors;\n\n        public bool HasValidators => _definition.Validators.Count != 0;\n\n        public IReadOnlyList<TriValidationResult> ValidationResults =>\n            _validationResults ?? EmptyValidationResults;\n\n        [PublicAPI]\n        public bool IsExpanded\n        {\n            get\n            {\n                if (_serializedProperty != null)\n                {\n                    return _serializedProperty.isExpanded;\n                }\n\n                if (_isExpandedPrefsKey == null)\n                {\n                    _isExpandedPrefsKey = $\"TriInspector.expanded.{PropertyPath}\";\n                }\n\n                return SessionState.GetBool(_isExpandedPrefsKey, false);\n            }\n            set\n            {\n                if (IsExpanded == value)\n                {\n                    return;\n                }\n\n                if (_serializedProperty != null)\n                {\n                    _serializedProperty.isExpanded = value;\n                }\n                else if (_isExpandedPrefsKey != null)\n                {\n                    SessionState.SetBool(_isExpandedPrefsKey, value);\n                }\n            }\n        }\n\n        [PublicAPI]\n        [CanBeNull]\n        public Type ValueType\n        {\n            get\n            {\n                if (PropertyType != TriPropertyType.Reference)\n                {\n                    return _definition.FieldType;\n                }\n\n                UpdateIfRequired();\n                return _valueType;\n            }\n        }\n\n        public bool IsValueMixed\n        {\n            get\n            {\n                if (PropertyTree.TargetsCount == 1)\n                {\n                    return false;\n                }\n\n                UpdateIfRequired();\n                return _isValueMixed;\n            }\n        }\n\n\n        [PublicAPI]\n        [CanBeNull]\n        public object Value\n        {\n            get\n            {\n                UpdateIfRequired();\n                return _value;\n            }\n        }\n\n        [PublicAPI]\n        public IReadOnlyList<TriProperty> ChildrenProperties\n        {\n            get\n            {\n                if (_childrenProperties != null && PropertyType == TriPropertyType.Generic)\n                {\n                    return _childrenProperties;\n                }\n\n                UpdateIfRequired();\n\n                return PropertyType == TriPropertyType.Generic || PropertyType == TriPropertyType.Reference\n                    ? _childrenProperties\n                    : throw new InvalidOperationException(\"Cannot read ChildrenProperties for \" + PropertyType);\n            }\n        }\n\n        [PublicAPI]\n        public IReadOnlyList<TriProperty> ArrayElementProperties\n        {\n            get\n            {\n                UpdateIfRequired();\n\n                return PropertyType == TriPropertyType.Array\n                    ? _childrenProperties\n                    : throw new InvalidOperationException(\"Cannot read ArrayElementProperties for \" + PropertyType);\n            }\n        }\n\n        [PublicAPI]\n        public bool TryGetMemberInfo(out MemberInfo memberInfo)\n        {\n            return _definition.TryGetMemberInfo(out memberInfo);\n        }\n\n        public object GetValue(int targetIndex)\n        {\n            return _definition.GetValue(this, targetIndex);\n        }\n\n        [PublicAPI]\n        public void SetValue(object value)\n        {\n            ModifyAndRecordForUndo(targetIndex => SetValueRecursive(this, value, targetIndex));\n        }\n\n        [PublicAPI]\n        public void SetValues(Func<int, object> getValue)\n        {\n            ModifyAndRecordForUndo(targetIndex =>\n            {\n                var value = getValue.Invoke(targetIndex);\n                SetValueRecursive(this, value, targetIndex);\n            });\n        }\n\n        public void ModifyAndRecordForUndo(Action<int> call)\n        {\n            PropertyTree.ApplyChanges();\n\n            PropertyTree.ForceCreateUndoGroup();\n\n            for (var targetIndex = 0; targetIndex < PropertyTree.TargetsCount; targetIndex++)\n            {\n                call.Invoke(targetIndex);\n            }\n\n            PropertyTree.Update(forceUpdate: true);\n\n            NotifyValueChanged();\n\n            PropertyTree.RequestValidation();\n            PropertyTree.RequestRepaint();\n        }\n\n        public void NotifyValueChanged()\n        {\n            NotifyValueChanged(this);\n        }\n\n        private void NotifyValueChanged(TriProperty property)\n        {\n            if (property == this)\n            {\n                ValueChanged?.Invoke(property);\n            }\n            else\n            {\n                ChildValueChanged?.Invoke(property);\n            }\n\n            Parent?.NotifyValueChanged(property);\n        }\n\n        private void UpdateIfRequired(bool forceUpdate = false)\n        {\n            if (_isUpdating)\n            {\n                throw new InvalidOperationException(\"Recursive call detected\");\n            }\n\n            if (_lastUpdateFrame == PropertyTree.RepaintFrame && !forceUpdate)\n            {\n                return;\n            }\n\n            _isUpdating = true;\n\n            try\n            {\n                _lastUpdateFrame = PropertyTree.RepaintFrame;\n\n                ReadValue(this, out var newValue, out var newValueIsMixed);\n\n                var newValueType = FieldType.IsValueType ? FieldType\n                    : ReferenceEquals(_value, newValue) ? _valueType\n                    : newValue?.GetType();\n                var valueTypeChanged = _valueType != newValueType;\n\n                _value = newValue;\n                _valueType = newValueType;\n                _isValueMixed = newValueIsMixed;\n\n                switch (PropertyType)\n                {\n                    case TriPropertyType.Generic:\n                    case TriPropertyType.Reference:\n                        if (_childrenProperties == null || valueTypeChanged)\n                        {\n                            if (_childrenProperties == null)\n                            {\n                                _childrenProperties = new List<TriProperty>();\n                            }\n\n                            _childrenProperties.Clear();\n\n                            var selfType = PropertyType == TriPropertyType.Reference ? _valueType : FieldType;\n                            if (selfType != null)\n                            {\n                                var properties = TriTypeDefinition.GetCached(selfType).Properties;\n                                for (var index = 0; index < properties.Count; index++)\n                                {\n                                    var childDefinition = properties[index];\n                                    var childSerializedProperty = _serializedProperty != null\n                                        ? _serializedProperty.FindPropertyRelative(childDefinition.Name)\n                                        : _serializedObject?.FindProperty(childDefinition.Name);\n                                    var childProperty = new TriProperty(PropertyTree, this,\n                                        childDefinition, index, childSerializedProperty);\n\n                                    _childrenProperties.Add(childProperty);\n                                }\n                            }\n                        }\n\n                        break;\n\n                    case TriPropertyType.Array:\n                        if (_childrenProperties == null)\n                        {\n                            _childrenProperties = new List<TriProperty>();\n                        }\n\n                        var listSize = ((IList)newValue)?.Count ?? 0;\n\n                        while (_childrenProperties.Count < listSize)\n                        {\n                            var index = _childrenProperties.Count;\n                            var elementDefinition = _definition.ArrayElementDefinition;\n                            var elementSerializedReference = _serializedProperty?.GetArrayElementAtIndex(index);\n\n                            var elementProperty = new TriProperty(PropertyTree, this,\n                                elementDefinition, index, elementSerializedReference);\n\n                            _childrenProperties.Add(elementProperty);\n                        }\n\n                        while (_childrenProperties.Count > listSize)\n                        {\n                            _childrenProperties.RemoveAt(_childrenProperties.Count - 1);\n                        }\n\n                        break;\n                }\n            }\n            finally\n            {\n                _isUpdating = false;\n            }\n        }\n\n        internal void RunValidation()\n        {\n            UpdateIfRequired();\n\n            if (HasValidators)\n            {\n                _validationResults = _definition.Validators\n                    .Select(it => it.Validate(this))\n                    .Where(it => !it.IsValid)\n                    .ToList();\n            }\n\n            if (_childrenProperties != null)\n            {\n                foreach (var childrenProperty in _childrenProperties)\n                {\n                    childrenProperty.RunValidation();\n                }\n            }\n        }\n\n        internal void EnumerateValidationResults(Action<TriProperty, TriValidationResult> call)\n        {\n            UpdateIfRequired();\n\n            if (_validationResults != null)\n            {\n                foreach (var result in _validationResults)\n                {\n                    call.Invoke(this, result);\n                }\n            }\n\n            if (_childrenProperties != null)\n            {\n                foreach (var childrenProperty in _childrenProperties)\n                {\n                    childrenProperty.EnumerateValidationResults(call);\n                }\n            }\n        }\n\n        [PublicAPI]\n        public bool TryGetSerializedProperty(out SerializedProperty serializedProperty)\n        {\n            serializedProperty = _serializedProperty;\n            return serializedProperty != null;\n        }\n\n        [PublicAPI]\n        public bool TryGetAttribute<TAttribute>(out TAttribute attribute)\n            where TAttribute : Attribute\n        {\n            if (ValueType != null)\n            {\n                foreach (var attr in TriReflectionUtilities.GetAttributesCached(ValueType))\n                {\n                    if (attr is TAttribute typedAttr)\n                    {\n                        attribute = typedAttr;\n                        return true;\n                    }\n                }\n            }\n\n            foreach (var attr in _definition.Attributes)\n            {\n                if (attr is TAttribute typedAttr)\n                {\n                    attribute = typedAttr;\n                    return true;\n                }\n            }\n\n            attribute = null;\n            return false;\n        }\n\n        internal static void BuildPropertyPath(TriProperty property, StringBuilder sb)\n        {\n            if (property.IsRootProperty)\n            {\n                return;\n            }\n\n            if (property.Parent != null && !property.Parent.IsRootProperty)\n            {\n                BuildPropertyPath(property.Parent, sb);\n                sb.Append('.');\n            }\n\n            if (property.IsArrayElement)\n            {\n                sb.Append(\"Array.data[\").Append(property.IndexInArray).Append(']');\n            }\n            else\n            {\n                sb.Append(property.RawName);\n            }\n        }\n\n        private static void SetValueRecursive(TriProperty property, object value, int targetIndex)\n        {\n            // for value types we must recursively set all parent objects\n            // because we cannot directly modify structs\n            // but we can re-set entire parent value\n            while (property._definition.SetValue(property, value, targetIndex, out var parentValue) &&\n                   property.Parent != null)\n            {\n                property = property.Parent;\n                value = parentValue;\n            }\n        }\n\n        private static void ReadValue(TriProperty property, out object newValue, out bool isMixed)\n        {\n            newValue = property.GetValue(0);\n\n            if (property.PropertyTree.TargetsCount == 1)\n            {\n                isMixed = false;\n                return;\n            }\n\n            switch (property.PropertyType)\n            {\n                case TriPropertyType.Array:\n                {\n                    var list = (IList)newValue;\n                    for (var i = 1; i < property.PropertyTree.TargetsCount; i++)\n                    {\n                        if (list == null)\n                        {\n                            break;\n                        }\n\n                        var otherList = (IList)property.GetValue(i);\n                        if (otherList == null || otherList.Count < list.Count)\n                        {\n                            newValue = list = otherList;\n                        }\n                    }\n\n                    isMixed = true;\n                    return;\n                }\n                case TriPropertyType.Reference:\n                {\n                    for (var i = 1; i < property.PropertyTree.TargetsCount; i++)\n                    {\n                        var otherValue = property.GetValue(i);\n\n                        if (newValue?.GetType() != otherValue?.GetType())\n                        {\n                            isMixed = true;\n                            newValue = null;\n                            return;\n                        }\n                    }\n\n                    isMixed = false;\n                    return;\n                }\n                case TriPropertyType.Generic:\n                {\n                    isMixed = false;\n                    return;\n                }\n                case TriPropertyType.Primitive:\n                {\n                    for (var i = 1; i < property.PropertyTree.TargetsCount; i++)\n                    {\n                        var otherValue = property.GetValue(i);\n                        if (!property.Comparer.Equals(otherValue, newValue))\n                        {\n                            isMixed = true;\n                            return;\n                        }\n                    }\n\n                    isMixed = false;\n                    return;\n                }\n\n                default:\n                {\n                    Debug.LogError($\"Unexpected property type: {property.PropertyType}\");\n                    isMixed = true;\n                    return;\n                }\n            }\n        }\n\n        private static TriPropertyType GetPropertyType(TriProperty property)\n        {\n            if (property._serializedProperty != null)\n            {\n                if (property._serializedProperty.isArray &&\n                    property._serializedProperty.propertyType != SerializedPropertyType.String)\n                {\n                    return TriPropertyType.Array;\n                }\n\n                if (property._serializedProperty.propertyType == SerializedPropertyType.ManagedReference)\n                {\n                    return TriPropertyType.Reference;\n                }\n\n                if (property._serializedProperty.propertyType == SerializedPropertyType.Generic)\n                {\n                    return TriPropertyType.Generic;\n                }\n\n                return TriPropertyType.Primitive;\n            }\n\n            if (property._serializedObject != null)\n            {\n                return TriPropertyType.Generic;\n            }\n\n            if (property._definition.FieldType.IsPrimitive ||\n                property._definition.FieldType == typeof(string) ||\n                typeof(UnityEngine.Object).IsAssignableFrom(property._definition.FieldType))\n            {\n                return TriPropertyType.Primitive;\n            }\n\n            if (property._definition.FieldType.IsValueType)\n            {\n                return TriPropertyType.Generic;\n            }\n\n            if (property._definition.IsArray)\n            {\n                return TriPropertyType.Array;\n            }\n\n            return TriPropertyType.Reference;\n        }\n    }\n\n    public enum TriPropertyType\n    {\n        Array,\n        Reference,\n        Generic,\n        Primitive,\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriProperty.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4db12eccd9e84863a9b3b445ce3ac85e\ntimeCreated: 1638862848"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyDefinition.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public class TriPropertyDefinition\n    {\n        private readonly ValueGetterDelegate _valueGetter;\n        [CanBeNull] private readonly ValueSetterDelegate _valueSetter;\n\n        private readonly List<string> _extensionErrors = new List<string>();\n        private readonly MemberInfo _memberInfo;\n        private readonly List<Attribute> _attributes;\n        private readonly bool _skipNullValuesFix;\n\n        private TriPropertyDefinition _arrayElementDefinitionBackingField;\n\n        private IReadOnlyList<TriCustomDrawer> _drawersBackingField;\n        private IReadOnlyList<TriValidator> _validatorsBackingField;\n        private IReadOnlyList<TriPropertyHideProcessor> _hideProcessorsBackingField;\n        private IReadOnlyList<TriPropertyDisableProcessor> _disableProcessorsBackingField;\n\n        public static TriPropertyDefinition CreateForFieldInfo(int order, FieldInfo fi)\n        {\n            return CreateForMemberInfo(fi, order, fi.Name, fi.FieldType, MakeGetter(fi), MakeSetter(fi));\n        }\n\n        public static TriPropertyDefinition CreateForPropertyInfo(int order, PropertyInfo pi)\n        {\n            return CreateForMemberInfo(pi, order, pi.Name, pi.PropertyType, MakeGetter(pi), MakeSetter(pi));\n        }\n\n        public static TriPropertyDefinition CreateForMethodInfo(int order, MethodInfo mi)\n        {\n            return CreateForMemberInfo(mi, order, mi.Name, typeof(MethodInfo), MakeGetter(mi), MakeSetter(mi));\n        }\n\n        private static TriPropertyDefinition CreateForMemberInfo(\n            MemberInfo memberInfo, int order, string propertyName, Type propertyType,\n            ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter)\n        {\n            var attributes = memberInfo?.GetCustomAttributes().ToList();\n            var ownerType = memberInfo?.DeclaringType ?? typeof(object);\n\n            return new TriPropertyDefinition(\n                memberInfo, ownerType, order, propertyName, propertyType, valueGetter, valueSetter, attributes, false);\n        }\n\n        public static TriPropertyDefinition CreateForGetterSetter(\n            int order, string name, Type fieldType,\n            ValueGetterDelegate valueGetter, ValueSetterDelegate valueSetter)\n        {\n            return new TriPropertyDefinition(\n                null, null, order, name, fieldType, valueGetter, valueSetter, null, false);\n        }\n\n        internal TriPropertyDefinition(\n            MemberInfo memberInfo,\n            Type ownerType,\n            int order,\n            string fieldName,\n            Type fieldType,\n            ValueGetterDelegate valueGetter,\n            ValueSetterDelegate valueSetter,\n            List<Attribute> attributes,\n            bool isArrayElement)\n        {\n            OwnerType = ownerType;\n            Name = fieldName;\n            FieldType = fieldType;\n            IsArrayElement = isArrayElement;\n\n            _attributes = attributes ?? new List<Attribute>();\n            _memberInfo = memberInfo;\n            _valueGetter = valueGetter;\n            _valueSetter = valueSetter;\n\n            _skipNullValuesFix = memberInfo != null && memberInfo.GetCustomAttribute<SerializeReference>() != null;\n\n            Order = order;\n            IsReadOnly = _valueSetter == null || Attributes.TryGet(out ReadOnlyAttribute _);\n\n            if (TriReflectionUtilities.IsArrayOrList(FieldType, out var elementType))\n            {\n                IsArray = true;\n                ArrayElementType = elementType;\n            }\n\n            if (Attributes.TryGet(out LabelTextAttribute labelTextAttribute))\n            {\n                CustomLabel = ValueResolver.ResolveString(this, labelTextAttribute.Text);\n            }\n\n            if (Attributes.TryGet(out PropertyTooltipAttribute tooltipAttribute))\n            {\n                CustomTooltip = ValueResolver.ResolveString(this, tooltipAttribute.Tooltip);\n            }\n            else if (Attributes.TryGet(out TooltipAttribute unityTooltipAttribute))\n            {\n                CustomTooltip = new ConstantValueResolver<string>(unityTooltipAttribute.tooltip);\n            }\n        }\n\n        public Type OwnerType { get; }\n\n        public Type FieldType { get; }\n\n        public string Name { get; }\n\n        public int Order { get; internal set; }\n\n        public IReadOnlyList<Attribute> Attributes => _attributes;\n\n        public bool IsReadOnly { get; }\n\n        public bool IsArrayElement { get; }\n        public Type ArrayElementType { get; }\n\n        public bool IsArray { get; }\n\n        [CanBeNull] public ValueResolver<string> CustomLabel { get; }\n        [CanBeNull] public ValueResolver<string> CustomTooltip { get; }\n\n        public IReadOnlyList<TriPropertyHideProcessor> HideProcessors => PopulateHideProcessor();\n        public IReadOnlyList<TriPropertyDisableProcessor> DisableProcessors => PopulateDisableProcessors();\n        public IReadOnlyList<TriCustomDrawer> Drawers => PopulateDrawers();\n        public IReadOnlyList<TriValidator> Validators => PopulateValidators();\n\n        internal IReadOnlyList<string> ExtensionErrors\n        {\n            get\n            {\n                PopulateHideProcessor();\n                PopulateDisableProcessors();\n                PopulateDrawers();\n                PopulateValidators();\n                return _extensionErrors;\n            }\n        }\n\n        public List<Attribute> GetEditableAttributes()\n        {\n            return _attributes;\n        }\n\n        public bool TryGetMemberInfo(out MemberInfo memberInfo)\n        {\n            memberInfo = _memberInfo;\n            return memberInfo != null;\n        }\n\n        public object GetValue(TriProperty property, int targetIndex)\n        {\n            var value = _valueGetter(property, targetIndex);\n\n            if (value == null && !_skipNullValuesFix)\n            {\n                value = TriUnitySerializationUtilities.PopulateUnityDefaultValueForType(FieldType);\n\n                if (value != null)\n                {\n                    _valueSetter?.Invoke(property, targetIndex, value);\n                }\n            }\n\n            return value;\n        }\n\n        public bool SetValue(TriProperty property, object value, int targetIndex, out object parentValue)\n        {\n            if (IsReadOnly)\n            {\n                Debug.LogError(\"Cannot set value for readonly property\");\n                parentValue = default;\n                return false;\n            }\n\n            parentValue = _valueSetter?.Invoke(property, targetIndex, value);\n            return true;\n        }\n\n        public TriPropertyDefinition ArrayElementDefinition\n        {\n            get\n            {\n                if (_arrayElementDefinitionBackingField == null)\n                {\n                    if (!IsArray)\n                    {\n                        throw new InvalidOperationException(\n                            $\"Cannot get array element definition for non array property: {FieldType}\");\n                    }\n\n                    var elementGetter = new ValueGetterDelegate((self, targetIndex) =>\n                    {\n                        var parentValue = (IList)self.Parent.GetValue(targetIndex);\n                        return parentValue[self.IndexInArray];\n                    });\n                    var elementSetter = new ValueSetterDelegate((self, targetIndex, value) =>\n                    {\n                        var parentValue = (IList)self.Parent.GetValue(targetIndex);\n                        parentValue[self.IndexInArray] = value;\n                        return parentValue;\n                    });\n\n                    _arrayElementDefinitionBackingField = new TriPropertyDefinition(_memberInfo, OwnerType, 0,\n                        \"Element\", ArrayElementType, elementGetter, elementSetter, _attributes, true);\n                }\n\n                return _arrayElementDefinitionBackingField;\n            }\n        }\n\n        private IReadOnlyList<TriPropertyHideProcessor> PopulateHideProcessor()\n        {\n            if (_hideProcessorsBackingField != null)\n            {\n                return _hideProcessorsBackingField;\n            }\n\n            return _hideProcessorsBackingField = TriDrawersUtilities\n                .CreateHideProcessorsFor(FieldType, Attributes)\n                .Where(CanApplyExtensionOnSelf)\n                .ToList();\n        }\n\n        private IReadOnlyList<TriPropertyDisableProcessor> PopulateDisableProcessors()\n        {\n            if (_disableProcessorsBackingField != null)\n            {\n                return _disableProcessorsBackingField;\n            }\n\n            return _disableProcessorsBackingField = TriDrawersUtilities\n                .CreateDisableProcessorsFor(FieldType, Attributes)\n                .Where(CanApplyExtensionOnSelf)\n                .ToList();\n        }\n\n        private IReadOnlyList<TriValidator> PopulateValidators()\n        {\n            if (_validatorsBackingField != null)\n            {\n                return _validatorsBackingField;\n            }\n\n            return _validatorsBackingField = Enumerable.Empty<TriValidator>()\n                .Concat(TriDrawersUtilities.CreateValueValidatorsFor(FieldType))\n                .Concat(TriDrawersUtilities.CreateAttributeValidatorsFor(FieldType, Attributes))\n                .Where(CanApplyExtensionOnSelf)\n                .ToList();\n        }\n\n        private IReadOnlyList<TriCustomDrawer> PopulateDrawers()\n        {\n            if (_drawersBackingField != null)\n            {\n                return _drawersBackingField;\n            }\n\n            return _drawersBackingField = Enumerable.Empty<TriCustomDrawer>()\n                .Concat(TriDrawersUtilities.CreateValueDrawersFor(FieldType))\n                .Concat(TriDrawersUtilities.CreateAttributeDrawersFor(FieldType, Attributes))\n                .Concat(new[]\n                {\n                    new ValidatorsDrawer { Order = TriDrawerOrder.Validator, },\n                })\n                .Where(CanApplyExtensionOnSelf)\n                .OrderBy(it => it.Order)\n                .ToList();\n        }\n\n        private static ValueGetterDelegate MakeGetter(FieldInfo fi)\n        {\n            return (self, targetIndex) =>\n            {\n                var parentValue = self.Parent.GetValue(targetIndex);\n                return fi.GetValue(parentValue);\n            };\n        }\n\n        private static ValueSetterDelegate MakeSetter(FieldInfo fi)\n        {\n            return (self, targetIndex, value) =>\n            {\n                var parentValue = self.Parent.GetValue(targetIndex);\n                fi.SetValue(parentValue, value);\n                return parentValue;\n            };\n        }\n\n        private static ValueGetterDelegate MakeGetter(PropertyInfo pi)\n        {\n            var method = pi.GetMethod;\n            return (self, targetIndex) =>\n            {\n                var parentValue = self.Parent.GetValue(targetIndex);\n                return method.Invoke(parentValue, null);\n            };\n        }\n\n        private static ValueSetterDelegate MakeSetter(PropertyInfo pi)\n        {\n            var method = pi.SetMethod;\n            if (method == null)\n            {\n                return null;\n            }\n\n            return (self, targetIndex, value) =>\n            {\n                var parentValue = self.Parent.GetValue(targetIndex);\n                method.Invoke(parentValue, new[] { value, });\n                return parentValue;\n            };\n        }\n\n        private static ValueGetterDelegate MakeGetter(MethodInfo mi)\n        {\n            return (self, targetIndex) => mi;\n        }\n\n        private static ValueSetterDelegate MakeSetter(MethodInfo mi)\n        {\n            return (self, targetIndex, value) =>\n            {\n                var parentValue = self.Parent.GetValue(targetIndex);\n                return parentValue;\n            };\n        }\n\n        private bool CanApplyExtensionOnSelf(TriPropertyExtension propertyExtension)\n        {\n            if (propertyExtension.ApplyOnArrayElement.HasValue)\n            {\n                if (IsArrayElement && !propertyExtension.ApplyOnArrayElement.Value ||\n                    IsArray && propertyExtension.ApplyOnArrayElement.Value)\n                {\n                    return false;\n                }\n            }\n\n            var result = propertyExtension.Initialize(this);\n            if (result.IsError)\n            {\n                _extensionErrors.Add(result.ErrorMessage);\n            }\n\n            return result.ShouldApply;\n        }\n\n        public delegate object ValueGetterDelegate(TriProperty self, int targetIndex);\n\n        public delegate object ValueSetterDelegate(TriProperty self, int targetIndex, object value);\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyDefinition.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4feaa123e82e4c93846c94ebd3af253e\ntimeCreated: 1638873323"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyDisableProcessor.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriPropertyDisableProcessor : TriPropertyExtension\n    {\n        internal Attribute RawAttribute { get; set; }\n\n        [PublicAPI]\n        public abstract bool IsDisabled(TriProperty property);\n    }\n\n    public abstract class TriPropertyDisableProcessor<TAttribute> : TriPropertyDisableProcessor\n        where TAttribute : Attribute\n    {\n        [PublicAPI]\n        public TAttribute Attribute => (TAttribute) RawAttribute;\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyDisableProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 2c01ea19c766412ba28df648a968abba\ntimeCreated: 1641385496"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyExtension.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriPropertyExtension\n    {\n        public bool? ApplyOnArrayElement { get; internal set; }\n\n        [PublicAPI]\n        public virtual TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            return TriExtensionInitializationResult.Ok;\n        }\n    }\n\n    public readonly struct TriExtensionInitializationResult\n    {\n        public TriExtensionInitializationResult(bool shouldApply, string errorMessage)\n        {\n            ShouldApply = shouldApply;\n            ErrorMessage = errorMessage;\n        }\n\n        public bool ShouldApply { get; }\n        public string ErrorMessage { get; }\n        public bool IsError => ErrorMessage != null;\n\n        [PublicAPI]\n        public static TriExtensionInitializationResult Ok => new TriExtensionInitializationResult(true, null);\n\n        [PublicAPI]\n        public static TriExtensionInitializationResult Skip => new TriExtensionInitializationResult(false, null);\n\n        [PublicAPI]\n        public static TriExtensionInitializationResult Error([NotNull] string errorMessage)\n        {\n            if (errorMessage == null)\n            {\n                throw new ArgumentNullException(nameof(errorMessage));\n            }\n\n            return new TriExtensionInitializationResult(false, errorMessage);\n        }\n\n        [PublicAPI]\n        public static implicit operator TriExtensionInitializationResult(string errorMessage)\n        {\n            return Error(errorMessage);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyExtension.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4da7122af7f84f1e8c0f2986e064e161\ntimeCreated: 1654255038"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyHideProcessor.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriPropertyHideProcessor : TriPropertyExtension\n    {\n        internal Attribute RawAttribute { get; set; }\n\n        [PublicAPI]\n        public abstract bool IsHidden(TriProperty property);\n    }\n\n    public abstract class TriPropertyHideProcessor<TAttribute> : TriPropertyHideProcessor\n        where TAttribute : Attribute\n    {\n        [PublicAPI]\n        public TAttribute Attribute => (TAttribute) RawAttribute;\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyHideProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: de11bb184a7d4c7f9c6a4f2a75756278\ntimeCreated: 1641384283"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyOverrideContext.cs",
    "content": "﻿using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriPropertyOverrideContext\n    {\n        private static TriPropertyOverrideContext Override { get; set; }\n        public static TriPropertyOverrideContext Current { get; private set; }\n\n        public abstract bool TryGetDisplayName(TriProperty property, out GUIContent displayName);\n\n        public static EnterPropertyScope BeginProperty()\n        {\n            return new EnterPropertyScope().Init();\n        }\n\n        public static OverrideScope BeginOverride(TriPropertyOverrideContext overrideContext)\n        {\n            return new OverrideScope(overrideContext);\n        }\n\n        public struct EnterPropertyScope\n        {\n            private TriPropertyOverrideContext _previousContext;\n\n            public EnterPropertyScope Init()\n            {\n                _previousContext = Current;\n                Current = Override;\n                Override = null;\n                return this;\n            }\n\n            public void EndProperty()\n            {\n                Override = Current;\n                Current = _previousContext;\n            }\n        }\n\n        public readonly struct OverrideScope : IDisposable\n        {\n            public OverrideScope(TriPropertyOverrideContext context)\n            {\n                if (Override != null)\n                {\n                    Debug.LogError($\"TriPropertyContext already overriden with {Override.GetType()}\");\n                }\n\n                Override = context;\n            }\n\n            public void Dispose()\n            {\n                Override = null;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyOverrideContext.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 009410b38db449a1a47369c87a015b0d\ntimeCreated: 1643555608"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyTree.cs",
    "content": "﻿using System;\nusing VirtueSky.Inspector.Elements;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Profiling;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriPropertyTree : IDisposable\n    {\n        private TriPropertyElement _rootPropertyElement;\n        private Rect _cachedOuterRect = new Rect(0, 0, 0, 0);\n\n        public TriPropertyDefinition RootPropertyDefinition { get; protected set; }\n        public TriProperty RootProperty { get; protected set; }\n\n        public Type TargetObjectType { get; protected set; }\n        public int TargetsCount { get; protected set; }\n        public bool TargetIsPersistent { get; protected set; }\n\n        public bool ValidationRequired { get; private set; } = true;\n        public bool RepaintRequired { get; private set; } = true;\n\n        public int RepaintFrame { get; private set; } = 0;\n\n        public virtual void Dispose()\n        {\n            if (_rootPropertyElement != null && _rootPropertyElement.IsAttached)\n            {\n                _rootPropertyElement.DetachInternal();\n            }\n        }\n\n        public virtual void Update(bool forceUpdate = false)\n        {\n            RepaintFrame++;\n        }\n\n        public virtual bool ApplyChanges()\n        {\n            return false;\n        }\n\n        public void RunValidationIfRequired()\n        {\n            if (!ValidationRequired)\n            {\n                return;\n            }\n\n            RunValidation();\n        }\n\n        public void RunValidation()\n        {\n            ValidationRequired = false;\n\n            Profiler.BeginSample(\"TriInspector.RunValidation\");\n            RootProperty.RunValidation();\n            Profiler.EndSample();\n\n            RequestRepaint();\n        }\n\n        public virtual void Draw()\n        {\n            RepaintRequired = false;\n\n            if (_rootPropertyElement == null)\n            {\n                _rootPropertyElement = new TriPropertyElement(RootProperty, new TriPropertyElement.Props\n                {\n                    forceInline = !RootProperty.TryGetMemberInfo(out _),\n                });\n                _rootPropertyElement.AttachInternal();\n            }\n\n            Profiler.BeginSample(\"TriInspector.UpdateRootPropertyElement\");\n            _rootPropertyElement.Update();\n            Profiler.EndSample();\n\n            var rectOuter = GUILayoutUtility.GetRect(0, 9999, 0, 0);\n            _cachedOuterRect = Event.current.type == EventType.Layout ? _cachedOuterRect : rectOuter;\n\n            var rect = new Rect(_cachedOuterRect);\n            rect = EditorGUI.IndentedRect(rect);\n            rect.height = _rootPropertyElement.GetHeight(rect.width);\n\n            var oldIndent = EditorGUI.indentLevel;\n            EditorGUI.indentLevel = 0;\n\n            GUILayoutUtility.GetRect(_cachedOuterRect.width, rect.height);\n\n            Profiler.BeginSample(\"TriInspector.DrawRootPropertyElement\");\n            _rootPropertyElement.OnGUI(rect);\n            Profiler.EndSample();\n\n            EditorGUI.indentLevel = oldIndent;\n        }\n\n        public void EnumerateValidationResults(Action<TriProperty, TriValidationResult> call)\n        {\n            RootProperty.EnumerateValidationResults(call);\n        }\n\n        public void RequestRepaint()\n        {\n            RepaintRequired = true;\n        }\n\n        public void RequestValidation()\n        {\n            ValidationRequired = true;\n\n            RequestRepaint();\n        }\n\n        public abstract void ForceCreateUndoGroup();\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyTree.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 9bb1d443163b4a26908eb26ba297c1d6\ntimeCreated: 1653126491"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyTreeForSerializedObject.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing JetBrains.Annotations;\nusing UnityEditor;\n\nnamespace VirtueSky.Inspector\n{\n    public sealed class TriPropertyTreeForSerializedObject : TriPropertyTree\n    {\n        private readonly SerializedObject _serializedObject;\n        private readonly SerializedProperty _scriptProperty;\n\n        public TriPropertyTreeForSerializedObject([NotNull] SerializedObject serializedObject)\n        {\n            _serializedObject = serializedObject ?? throw new ArgumentNullException(nameof(serializedObject));\n            _scriptProperty = serializedObject.FindProperty(\"m_Script\");\n\n            TargetObjectType = _serializedObject.targetObject.GetType();\n            TargetsCount = _serializedObject.targetObjects.Length;\n            TargetIsPersistent = _serializedObject.targetObject is var targetObject &&\n                                 targetObject != null && EditorUtility.IsPersistent(targetObject);\n\n            RootPropertyDefinition = new TriPropertyDefinition(\n                memberInfo: null,\n                ownerType: null,\n                order: -1,\n                fieldName: \"ROOT\",\n                fieldType: TargetObjectType,\n                valueGetter: (self, targetIndex) => _serializedObject.targetObjects[targetIndex],\n                valueSetter: (self, targetIndex, value) => _serializedObject.targetObjects[targetIndex],\n                attributes: new List<Attribute>(),\n                isArrayElement: false);\n\n            RootProperty = new TriProperty(this, null, RootPropertyDefinition, serializedObject);\n\n            RootProperty.ValueChanged += OnPropertyChanged;\n            RootProperty.ChildValueChanged += OnPropertyChanged;\n        }\n\n        public override void Dispose()\n        {\n            RootProperty.ChildValueChanged -= OnPropertyChanged;\n            RootProperty.ValueChanged -= OnPropertyChanged;\n\n            base.Dispose();\n        }\n\n        public override void Update(bool forceUpdate = false)\n        {\n            if (forceUpdate)\n            {\n                _serializedObject.SetIsDifferentCacheDirty();\n                _serializedObject.Update();\n            }\n\n            base.Update(forceUpdate);\n        }\n\n        public override void Draw()\n        {\n            DrawMonoScriptProperty();\n\n            base.Draw();\n        }\n\n        public override bool ApplyChanges()\n        {\n            var changed = base.ApplyChanges();\n            changed |= _serializedObject.ApplyModifiedProperties();\n            return changed;\n        }\n\n        public override void ForceCreateUndoGroup()\n        {\n            Undo.RegisterCompleteObjectUndo(_serializedObject.targetObjects, \"Inspector\");\n            Undo.FlushUndoRecordObjects();\n        }\n\n        private void OnPropertyChanged(TriProperty changedProperty)\n        {\n            foreach (var targetObject in _serializedObject.targetObjects)\n            {\n                EditorUtility.SetDirty(targetObject);\n            }\n\n            RequestValidation();\n            RequestRepaint();\n        }\n\n        private void DrawMonoScriptProperty()\n        {\n            if (RootProperty.TryGetAttribute(out HideMonoScriptAttribute _))\n            {\n                return;\n            }\n\n            EditorGUI.BeginDisabledGroup(true);\n            var scriptRect = EditorGUILayout.GetControlRect(true);\n            scriptRect.xMin += 3;\n            EditorGUI.PropertyField(scriptRect, _scriptProperty);\n            EditorGUI.EndDisabledGroup();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriPropertyTreeForSerializedObject.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 468b264c3e164c0681760c3d98451466\ntimeCreated: 1638857169"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriTypeDefinition.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VirtueSky.Inspector.Utilities;\n\nnamespace VirtueSky.Inspector\n{\n    public class TriTypeDefinition\n    {\n        private static readonly Dictionary<Type, TriTypeDefinition> Cache =\n            new Dictionary<Type, TriTypeDefinition>();\n\n        private TriTypeDefinition(IReadOnlyList<TriPropertyDefinition> properties)\n        {\n            Properties = properties;\n        }\n\n        public IReadOnlyList<TriPropertyDefinition> Properties { get; }\n\n        public static TriTypeDefinition GetCached(Type type)\n        {\n            if (Cache.TryGetValue(type, out var definition))\n            {\n                return definition;\n            }\n\n            var processors = TriDrawersUtilities.AllTypeProcessors;\n            var properties = new List<TriPropertyDefinition>();\n\n            foreach (var processor in processors)\n            {\n                processor.ProcessType(type, properties);\n            }\n\n            return Cache[type] = new TriTypeDefinition(properties);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriTypeDefinition.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 034ca4c8b571472fb71db422a48cfe07\ntimeCreated: 1638870763"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriTypeProcessor\n    {\n        public abstract void ProcessType(Type type, List<TriPropertyDefinition> properties);\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriTypeProcessor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0a7c26cf735e465d8373066f830cf5c4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriValidator.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriValidator : TriPropertyExtension\n    {\n        [PublicAPI]\n        public abstract TriValidationResult Validate(TriProperty property);\n    }\n\n    public abstract class TriAttributeValidator : TriValidator\n    {\n        internal Attribute RawAttribute { get; set; }\n    }\n\n    public abstract class TriAttributeValidator<TAttribute> : TriAttributeValidator\n        where TAttribute : Attribute\n    {\n        [PublicAPI]\n        public TAttribute Attribute => (TAttribute) RawAttribute;\n    }\n\n    public abstract class TriValueValidator : TriValidator\n    {\n    }\n\n    public abstract class TriValueValidator<T> : TriValueValidator\n    {\n        public sealed override TriValidationResult Validate(TriProperty property)\n        {\n            return Validate(new TriValue<T>(property));\n        }\n\n        [PublicAPI]\n        public abstract TriValidationResult Validate(TriValue<T> propertyValue);\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: b90ba6bdef614e9aa246f371506ea113\ntimeCreated: 1642260754"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriValue.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector\n{\n    public struct TriValue<T>\n    {\n        internal TriValue(TriProperty property)\n        {\n            Property = property;\n        }\n\n        public TriProperty Property { get; }\n\n        [Obsolete(\"Use SmartValue instead\", true)]\n        public T Value\n        {\n            get => (T) Property.Value;\n            set => Property.SetValue(value);\n        }\n\n        [PublicAPI]\n        public T SmartValue\n        {\n            get => (T) Property.Value;\n            set\n            {\n                if (Property.Comparer.Equals(Property.Value, value))\n                {\n                    return;\n                }\n\n                Property.SetValue(value);\n            }\n        }\n\n        [PublicAPI]\n        public void SetValue(T value)\n        {\n            Property.SetValue(value);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriValue.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a925dd69982048009ab567f0b75ec326\ntimeCreated: 1639381003"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriValueDrawer.cs",
    "content": "﻿using JetBrains.Annotations;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class TriValueDrawer : TriCustomDrawer\n    {\n    }\n\n    public abstract class TriValueDrawer<TValue> : TriValueDrawer\n    {\n        public sealed override TriElement CreateElementInternal(TriProperty property, TriElement next)\n        {\n            return CreateElement(new TriValue<TValue>(property), next);\n        }\n\n        [PublicAPI]\n        public virtual TriElement CreateElement(TriValue<TValue> propertyValue, TriElement next)\n        {\n            return new DefaultValueDrawerElement<TValue>(this, propertyValue, next);\n        }\n\n        [PublicAPI]\n        public virtual float GetHeight(float width, TriValue<TValue> propertyValue, TriElement next)\n        {\n            return next.GetHeight(width);\n        }\n\n        [PublicAPI]\n        public virtual void OnGUI(Rect position, TriValue<TValue> propertyValue, TriElement next)\n        {\n            next.OnGUI(position);\n        }\n\n        internal class DefaultValueDrawerElement<T> : TriElement\n        {\n            private readonly TriValueDrawer<T> _drawer;\n            private readonly TriElement _next;\n            private readonly TriValue<T> _propertyValue;\n\n            public DefaultValueDrawerElement(TriValueDrawer<T> drawer, TriValue<T> propertyValue, TriElement next)\n            {\n                _drawer = drawer;\n                _propertyValue = propertyValue;\n                _next = next;\n\n                AddChild(next);\n            }\n\n            public override float GetHeight(float width)\n            {\n                return _drawer.GetHeight(width, _propertyValue, _next);\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                _drawer.OnGUI(position, _propertyValue, _next);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TriValueDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: dfd7988d91ca4f879f888735018e9116\ntimeCreated: 1639381337"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriGroupNextTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing VirtueSky.Inspector.Utilities;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriGroupNextTypeProcessor), 11000)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriGroupNextTypeProcessor : TriTypeProcessor\n    {\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            TriPropertyDefinition groupProperty = null;\n            GroupAttribute groupAttribute = null;\n            TabAttribute tabAttribute = null;\n\n            foreach (var property in properties)\n            {\n                if (groupProperty != null)\n                {\n                    if (groupProperty.OwnerType != property.OwnerType ||\n                        groupProperty.Order + 1000 < property.Order)\n                    {\n                        groupProperty = null;\n                        groupAttribute = null;\n                        tabAttribute = null;\n                    }\n                }\n\n                if (property.Attributes.TryGet(out GroupNextAttribute groupNextAttribute))\n                {\n                    groupProperty = property;\n\n                    groupAttribute = groupNextAttribute.Path != null\n                        ? new GroupAttribute(groupNextAttribute.Path)\n                        : null;\n\n                    property.Attributes.TryGet(out tabAttribute);\n                }\n\n                if (groupAttribute != null && !property.Attributes.TryGet(out GroupAttribute _))\n                {\n                    property.GetEditableAttributes().Add(groupAttribute);\n                }\n\n                if (tabAttribute != null && !property.Attributes.TryGet(out TabAttribute _))\n                {\n                    property.GetEditableAttributes().Add(tabAttribute);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriGroupNextTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ef78c1a907f144a4bedc9cf2433d2526\ntimeCreated: 1660802896"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRectOffsetTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing UnityEngine;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriRectOffsetTypeProcessor), 1)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriRectOffsetTypeProcessor : TriTypeProcessor\n    {\n        private static readonly string[] DrawnProperties = new[]\n        {\n            \"left\",\n            \"right\",\n            \"top\",\n            \"bottom\",\n        };\n\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            if (type != typeof(RectOffset))\n            {\n                return;\n            }\n\n            for (var i = 0; i < DrawnProperties.Length; i++)\n            {\n                var propertyName = DrawnProperties[i];\n                var propertyInfo = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);\n                var propertyDef = TriPropertyDefinition.CreateForPropertyInfo(i, propertyInfo);\n\n                properties.Add(propertyDef);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRectOffsetTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 83fc30fabc614cb7a2501332802a2094\ntimeCreated: 1676534091"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterButtonsTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing VirtueSky.Inspector.Utilities;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriRegisterButtonsTypeProcessor), 3)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriRegisterButtonsTypeProcessor : TriTypeProcessor\n    {\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            const int methodsOffset = 20001;\n\n            properties.AddRange(TriReflectionUtilities\n                .GetAllInstanceMethodsInDeclarationOrder(type)\n                .Where(IsSerialized)\n                .Select((it, ind) => TriPropertyDefinition.CreateForMethodInfo(ind + methodsOffset, it)));\n        }\n\n        private static bool IsSerialized(MethodInfo methodInfo)\n        {\n            return methodInfo.GetCustomAttribute<ButtonAttribute>(false) != null;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterButtonsTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: abe3b6771e754b2da1b3d226784ad02e\ntimeCreated: 1660755911"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriFieldsTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing VirtueSky.Inspector.Utilities;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriRegisterShownByTriFieldsTypeProcessor), 1)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriRegisterShownByTriFieldsTypeProcessor : TriTypeProcessor\n    {\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            const int fieldsOffset = 5001;\n\n            properties.AddRange(TriReflectionUtilities\n                .GetAllInstanceFieldsInDeclarationOrder(type)\n                .Where(IsSerialized)\n                .Select((it, ind) => TriPropertyDefinition.CreateForFieldInfo(ind + fieldsOffset, it)));\n        }\n\n        private static bool IsSerialized(FieldInfo fieldInfo)\n        {\n            return fieldInfo.GetCustomAttribute<ShowInInspectorAttribute>(false) != null &&\n                   TriUnitySerializationUtilities.IsSerializableByUnity(fieldInfo) == false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriFieldsTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d5a485127f534bee963f620f86287c34\ntimeCreated: 1670601276"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriPropertiesTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing VirtueSky.Inspector.Utilities;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriRegisterShownByTriPropertiesTypeProcessor), 1)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriRegisterShownByTriPropertiesTypeProcessor : TriTypeProcessor\n    {\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            const int propertiesOffset = 10001;\n\n            properties.AddRange(TriReflectionUtilities\n                .GetAllInstancePropertiesInDeclarationOrder(type)\n                .Where(IsSerialized)\n                .Select((it, ind) => TriPropertyDefinition.CreateForPropertyInfo(ind + propertiesOffset, it)));\n        }\n\n        private static bool IsSerialized(PropertyInfo propertyInfo)\n        {\n            return propertyInfo.GetCustomAttribute<ShowInInspectorAttribute>(false) != null;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterShownByTriPropertiesTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c57e9a6e1c4e46558fb3c43ffb404a57\ntimeCreated: 1660755901"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterUnitySerializedFieldsTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing VirtueSky.Inspector.Utilities;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriRegisterUnitySerializedFieldsTypeProcessor), 0)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriRegisterUnitySerializedFieldsTypeProcessor : TriTypeProcessor\n    {\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            const int fieldsOffset = 1;\n\n            properties.AddRange(TriReflectionUtilities\n                .GetAllInstanceFieldsInDeclarationOrder(type)\n                .Where(IsSerialized)\n                .Select((it, ind) => TriPropertyDefinition.CreateForFieldInfo(ind + fieldsOffset, it)));\n        }\n\n        private static bool IsSerialized(FieldInfo fieldInfo)\n        {\n            return TriUnitySerializationUtilities.IsSerializableByUnity(fieldInfo);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriRegisterUnitySerializedFieldsTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 5a19f117ac85440cb8896b8b90a9f17a\ntimeCreated: 1660755421"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriSortPropertiesTypeProcessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.TypeProcessors;\nusing VirtueSky.Inspector.Utilities;\n\n[assembly: RegisterTriTypeProcessor(typeof(TriSortPropertiesTypeProcessor), 10000)]\n\nnamespace VirtueSky.Inspector.TypeProcessors\n{\n    public class TriSortPropertiesTypeProcessor : TriTypeProcessor\n    {\n        public override void ProcessType(Type type, List<TriPropertyDefinition> properties)\n        {\n            foreach (var propertyDefinition in properties)\n            {\n                if (propertyDefinition.Attributes.TryGet(out PropertyOrderAttribute orderAttribute))\n                {\n                    propertyDefinition.Order = orderAttribute.Order;\n                }\n            }\n\n            properties.Sort(PropertyOrderComparer.Instance);\n        }\n\n        private class PropertyOrderComparer : IComparer<TriPropertyDefinition>\n        {\n            public static readonly PropertyOrderComparer Instance = new PropertyOrderComparer();\n\n            public int Compare(TriPropertyDefinition x, TriPropertyDefinition y)\n            {\n                return x.Order.CompareTo(y.Order);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors/TriSortPropertiesTypeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 900dee18b5e245198d1891d10d0a954b\ntimeCreated: 1660756062"
  },
  {
    "path": "VirtueSky/Inspector/Editor/TypeProcessors.meta",
    "content": "fileFormatVersion: 2\nguid: 52aec2fc04054420970349733f05237b\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriAttributeUtilities.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    internal static class TriAttributeUtilities\n    {\n        public static bool TryGet<T>(this IReadOnlyList<Attribute> attributes, out T it)\n            where T : Attribute\n        {\n            foreach (var attribute in attributes)\n            {\n                if (attribute is T typeAttribute)\n                {\n                    it = typeAttribute;\n                    return true;\n                }\n            }\n\n            it = null;\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriAttributeUtilities.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ff3eb732102046b0b36e76f9d17cab4e\ntimeCreated: 1638876778"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriDrawersUtilities.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing VirtueSky.Inspector.Elements;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    internal class TriDrawersUtilities\n    {\n        private static readonly GenericTypeMatcher GroupDrawerMatcher = typeof(TriGroupDrawer<>);\n        private static readonly GenericTypeMatcher ValueDrawerMatcher = typeof(TriValueDrawer<>);\n        private static readonly GenericTypeMatcher AttributeDrawerMatcher = typeof(TriAttributeDrawer<>);\n        private static readonly GenericTypeMatcher ValueValidatorMatcher = typeof(TriValueValidator<>);\n        private static readonly GenericTypeMatcher AttributeValidatorMatcher = typeof(TriAttributeValidator<>);\n        private static readonly GenericTypeMatcher HideProcessorMatcher = typeof(TriPropertyHideProcessor<>);\n        private static readonly GenericTypeMatcher DisableProcessorMatcher = typeof(TriPropertyDisableProcessor<>);\n\n        private static IDictionary<Type, TriGroupDrawer> _allGroupDrawersCacheBackingField;\n        private static IReadOnlyList<RegisterTriAttributeDrawerAttribute> _allAttributeDrawerTypesBackingField;\n        private static IReadOnlyList<RegisterTriValueDrawerAttribute> _allValueDrawerTypesBackingField;\n        private static IReadOnlyList<RegisterTriAttributeValidatorAttribute> _allAttributeValidatorTypesBackingField;\n        private static IReadOnlyList<RegisterTriValueValidatorAttribute> _allValueValidatorTypesBackingField;\n        private static IReadOnlyList<RegisterTriPropertyHideProcessor> _allHideProcessorTypesBackingField;\n        private static IReadOnlyList<RegisterTriPropertyDisableProcessor> _allDisableProcessorTypesBackingField;\n\n        private static IReadOnlyList<TriTypeProcessor> _allTypeProcessorBackingField;\n\n        private static IDictionary<Type, TriGroupDrawer> AllGroupDrawersCache\n        {\n            get\n            {\n                if (_allGroupDrawersCacheBackingField == null)\n                {\n                    _allGroupDrawersCacheBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriGroupDrawerAttribute>()\n                        let groupAttributeType = GroupDrawerMatcher.MatchOut(attr.DrawerType, out var t) ? t : null\n                        where groupAttributeType != null\n                        select new KeyValuePair<Type, RegisterTriGroupDrawerAttribute>(groupAttributeType, attr)\n                    ).ToDictionary(\n                        it => it.Key,\n                        it => (TriGroupDrawer) Activator.CreateInstance(it.Value.DrawerType));\n                }\n\n                return _allGroupDrawersCacheBackingField;\n            }\n        }\n\n        public static IReadOnlyList<TriTypeProcessor> AllTypeProcessors\n        {\n            get\n            {\n                if (_allTypeProcessorBackingField == null)\n                {\n                    _allTypeProcessorBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriTypeProcessorAttribute>()\n                        orderby attr.Order\n                        select (TriTypeProcessor) Activator.CreateInstance(attr.ProcessorType)\n                    ).ToList();\n                }\n\n                return _allTypeProcessorBackingField;\n            }\n        }\n\n        public static IReadOnlyList<RegisterTriValueDrawerAttribute> AllValueDrawerTypes\n        {\n            get\n            {\n                if (_allValueDrawerTypesBackingField == null)\n                {\n                    _allValueDrawerTypesBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriValueDrawerAttribute>()\n                        where ValueDrawerMatcher.Match(attr.DrawerType)\n                        select attr\n                    ).ToList();\n                }\n\n                return _allValueDrawerTypesBackingField;\n            }\n        }\n\n        public static IReadOnlyList<RegisterTriAttributeDrawerAttribute> AllAttributeDrawerTypes\n        {\n            get\n            {\n                if (_allAttributeDrawerTypesBackingField == null)\n                {\n                    _allAttributeDrawerTypesBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriAttributeDrawerAttribute>()\n                        where AttributeDrawerMatcher.Match(attr.DrawerType)\n                        select attr\n                    ).ToList();\n                }\n\n                return _allAttributeDrawerTypesBackingField;\n            }\n        }\n\n        public static IReadOnlyList<RegisterTriValueValidatorAttribute> AllValueValidatorTypes\n        {\n            get\n            {\n                if (_allValueValidatorTypesBackingField == null)\n                {\n                    _allValueValidatorTypesBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriValueValidatorAttribute>()\n                        where ValueValidatorMatcher.Match(attr.ValidatorType)\n                        select attr\n                    ).ToList();\n                }\n\n                return _allValueValidatorTypesBackingField;\n            }\n        }\n\n        public static IReadOnlyList<RegisterTriAttributeValidatorAttribute> AllAttributeValidatorTypes\n        {\n            get\n            {\n                if (_allAttributeValidatorTypesBackingField == null)\n                {\n                    _allAttributeValidatorTypesBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriAttributeValidatorAttribute>()\n                        where AttributeValidatorMatcher.Match(attr.ValidatorType)\n                        select attr\n                    ).ToList();\n                }\n\n                return _allAttributeValidatorTypesBackingField;\n            }\n        }\n\n        public static IReadOnlyList<RegisterTriPropertyHideProcessor> AllHideProcessors\n        {\n            get\n            {\n                if (_allHideProcessorTypesBackingField == null)\n                {\n                    _allHideProcessorTypesBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriPropertyHideProcessor>()\n                        where HideProcessorMatcher.Match(attr.ProcessorType)\n                        select attr\n                    ).ToList();\n                }\n\n                return _allHideProcessorTypesBackingField;\n            }\n        }\n\n        public static IReadOnlyList<RegisterTriPropertyDisableProcessor> AllDisableProcessors\n        {\n            get\n            {\n                if (_allDisableProcessorTypesBackingField == null)\n                {\n                    _allDisableProcessorTypesBackingField = (\n                        from asm in TriReflectionUtilities.Assemblies\n                        from attr in asm.GetCustomAttributes<RegisterTriPropertyDisableProcessor>()\n                        where DisableProcessorMatcher.Match(attr.ProcessorType)\n                        select attr\n                    ).ToList();\n                }\n\n                return _allDisableProcessorTypesBackingField;\n            }\n        }\n\n        public static TriPropertyCollectionBaseElement TryCreateGroupElementFor(DeclareGroupBaseAttribute attribute)\n        {\n            if (!AllGroupDrawersCache.TryGetValue(attribute.GetType(), out var attr))\n            {\n                return null;\n            }\n\n            return attr.CreateElementInternal(attribute);\n        }\n\n        public static IEnumerable<TriValueDrawer> CreateValueDrawersFor(Type valueType)\n        {\n            return\n                from drawer in AllValueDrawerTypes\n                where ValueDrawerMatcher.Match(drawer.DrawerType, valueType)\n                select CreateInstance<TriValueDrawer>(drawer.DrawerType, valueType, it =>\n                {\n                    it.ApplyOnArrayElement = drawer.ApplyOnArrayElement;\n                    it.Order = drawer.Order;\n                });\n        }\n\n        public static IEnumerable<TriAttributeDrawer> CreateAttributeDrawersFor(\n            Type valueType, IReadOnlyList<Attribute> attributes)\n        {\n            return\n                from attribute in attributes\n                from drawer in AllAttributeDrawerTypes\n                where AttributeDrawerMatcher.Match(drawer.DrawerType, attribute.GetType())\n                select CreateInstance<TriAttributeDrawer>(drawer.DrawerType, valueType, it =>\n                {\n                    it.ApplyOnArrayElement = drawer.ApplyOnArrayElement;\n                    it.Order = drawer.Order;\n                    it.RawAttribute = attribute;\n                });\n        }\n\n        public static IEnumerable<TriValueValidator> CreateValueValidatorsFor(Type valueType)\n        {\n            return\n                from validator in AllValueValidatorTypes\n                where ValueValidatorMatcher.Match(validator.ValidatorType, valueType)\n                select CreateInstance<TriValueValidator>(validator.ValidatorType, valueType, it =>\n                {\n                    //\n                    it.ApplyOnArrayElement = validator.ApplyOnArrayElement;\n                });\n        }\n\n        public static IEnumerable<TriAttributeValidator> CreateAttributeValidatorsFor(\n            Type valueType, IReadOnlyList<Attribute> attributes)\n        {\n            return\n                from attribute in attributes\n                from validator in AllAttributeValidatorTypes\n                where AttributeValidatorMatcher.Match(validator.ValidatorType, attribute.GetType())\n                select CreateInstance<TriAttributeValidator>(validator.ValidatorType, valueType, it =>\n                {\n                    it.ApplyOnArrayElement = validator.ApplyOnArrayElement;\n                    it.RawAttribute = attribute;\n                });\n        }\n\n        public static IEnumerable<TriPropertyHideProcessor> CreateHideProcessorsFor(\n            Type valueType, IReadOnlyList<Attribute> attributes)\n        {\n            return\n                from attribute in attributes\n                from processor in AllHideProcessors\n                where HideProcessorMatcher.Match(processor.ProcessorType, attribute.GetType())\n                select CreateInstance<TriPropertyHideProcessor>(\n                    processor.ProcessorType, valueType, it =>\n                    {\n                        it.ApplyOnArrayElement = processor.ApplyOnArrayElement;\n                        it.RawAttribute = attribute;\n                    });\n        }\n\n        public static IEnumerable<TriPropertyDisableProcessor> CreateDisableProcessorsFor(\n            Type valueType, IReadOnlyList<Attribute> attributes)\n        {\n            return\n                from attribute in attributes\n                from processor in AllDisableProcessors\n                where DisableProcessorMatcher.Match(processor.ProcessorType, attribute.GetType())\n                select CreateInstance<TriPropertyDisableProcessor>(\n                    processor.ProcessorType, valueType, it =>\n                    {\n                        it.ApplyOnArrayElement = processor.ApplyOnArrayElement;\n                        it.RawAttribute = attribute;\n                    });\n        }\n\n        private static T CreateInstance<T>(Type type, Type argType, Action<T> setup)\n        {\n            if (type.IsGenericType)\n            {\n                type = type.MakeGenericType(argType);\n            }\n\n            var instance = (T) Activator.CreateInstance(type);\n            setup(instance);\n            return instance;\n        }\n\n        private class GenericTypeMatcher\n        {\n            private readonly Dictionary<Type, (bool, Type)> _cache = new Dictionary<Type, (bool, Type)>();\n            private readonly Type _expectedGenericType;\n\n            private GenericTypeMatcher(Type expectedGenericType)\n            {\n                _expectedGenericType = expectedGenericType;\n            }\n\n            public static implicit operator GenericTypeMatcher(Type expectedGenericType)\n            {\n                return new GenericTypeMatcher(expectedGenericType);\n            }\n\n            public bool Match(Type type, Type targetType)\n            {\n                return MatchOut(type, out var constraint) &&\n                       constraint.IsAssignableFrom(targetType);\n            }\n\n            public bool Match(Type type)\n            {\n                return MatchOut(type, out _);\n            }\n\n            public bool MatchOut(Type type, out Type targetType)\n            {\n                if (_cache.TryGetValue(type, out var cachedResult))\n                {\n                    targetType = cachedResult.Item2;\n                    return cachedResult.Item1;\n                }\n\n                var succeed = MatchInternal(type, out targetType);\n                _cache[type] = (succeed, targetType);\n                return succeed;\n            }\n\n            private bool MatchInternal(Type type, out Type targetType)\n            {\n                targetType = null;\n\n                if (type.IsAbstract)\n                {\n                    Debug.LogError($\"{type.Name} must be non abstract\");\n                    return false;\n                }\n\n                if (type.GetConstructor(Type.EmptyTypes) == null)\n                {\n                    Debug.LogError($\"{type.Name} must have a parameterless constructor\");\n                    return false;\n                }\n\n                Type genericArgConstraints = null;\n                if (type.IsGenericType)\n                {\n                    var genericArg = type.GetGenericArguments().SingleOrDefault();\n\n                    if (genericArg == null ||\n                        genericArg.GenericParameterAttributes != GenericParameterAttributes.None)\n                    {\n                        Debug.LogError(\n                            $\"{type.Name} must contains only one generic arg with simple constant e.g. <where T : bool>\");\n                        return false;\n                    }\n\n                    genericArgConstraints = genericArg.GetGenericParameterConstraints().SingleOrDefault();\n                }\n\n                var drawerType = type.BaseType;\n\n                while (drawerType != null)\n                {\n                    if (drawerType.IsGenericType &&\n                        drawerType.GetGenericTypeDefinition() == _expectedGenericType)\n                    {\n                        targetType = drawerType.GetGenericArguments()[0];\n\n                        if (targetType.IsGenericParameter)\n                        {\n                            if (genericArgConstraints == null)\n                            {\n                                Debug.LogError(\n                                    $\"{type.Name} must contains only one generic arg with simple constant e.g. <where T : bool>\");\n                                return false;\n                            }\n\n                            targetType = genericArgConstraints;\n                        }\n\n                        return true;\n                    }\n\n                    drawerType = drawerType.BaseType;\n                }\n\n                Debug.LogError($\"{type.Name} must implement {_expectedGenericType}\");\n                return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriDrawersUtilities.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: fbb9d9e8efd64dedb3b04ab3f90317f7\ntimeCreated: 1638886023"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriEditorGUI.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    public static class TriEditorGUI\n    {\n        public static void Foldout(Rect rect, TriProperty property)\n        {\n            var content = property.DisplayNameContent;\n            if (property.TryGetSerializedProperty(out var serializedProperty))\n            {\n                EditorGUI.BeginProperty(rect, content, serializedProperty);\n                property.IsExpanded = EditorGUI.Foldout(rect, property.IsExpanded, content, true);\n                EditorGUI.EndProperty();\n            }\n            else\n            {\n                property.IsExpanded = EditorGUI.Foldout(rect, property.IsExpanded, content, true);\n            }\n        }\n\n        public static void DrawBox(Rect position, GUIStyle style,\n            bool isHover = false, bool isActive = false, bool on = false, bool hasKeyboardFocus = false)\n        {\n            if (Event.current.type == EventType.Repaint)\n            {\n                style.Draw(position, GUIContent.none, isHover, isActive, on, hasKeyboardFocus);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriEditorGUI.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 59bc827ebe19464ea936ff5cf8ae1b7f\ntimeCreated: 1638864333"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriEqualityComparer.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Reflection;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    public static class TriEqualityComparer\n    {\n        private static readonly Dictionary<Type, IEqualityComparer> Cache = new Dictionary<Type, IEqualityComparer>();\n\n        public static IEqualityComparer Of(Type type)\n        {\n            if (!Cache.TryGetValue(type, out var comparer))\n            {\n                Cache[type] = comparer = CreateDefaultEqualityComparer(type);\n            }\n\n            return comparer;\n        }\n\n        private static IEqualityComparer CreateDefaultEqualityComparer(Type type)\n        {\n            var comparerType = typeof(EqualityComparer<>).MakeGenericType(type);\n            var comparerProperty = comparerType.GetProperty(\"Default\", BindingFlags.Static | BindingFlags.Public);\n            var comparer = (IEqualityComparer) comparerProperty?.GetValue(null);\n\n            if (comparer == null)\n            {\n                throw new InvalidOperationException($\"Failed to create default comparer for type {type}\");\n            }\n            \n            return comparer;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriEqualityComparer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 47b9c566490541bcbfcf7fc93bf7bdea\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriGuiHelper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    public static class TriGuiHelper\n    {\n        private static readonly GUIContent TempContentShared = new GUIContent();\n        private static readonly Stack<Object> TargetObjects = new Stack<Object>();\n\n        public static GUIContent TempContent(string text)\n        {\n            TempContentShared.text = text;\n            return TempContentShared;\n        }\n\n        internal static bool IsAnyEditorPushed()\n        {\n            return TargetObjects.Count > 0;\n        }\n\n        internal static bool IsEditorTargetPushed(Object obj)\n        {\n            foreach (var targetObject in TargetObjects)\n            {\n                if (targetObject == obj)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        internal static EditorScope PushEditorTarget(Object obj)\n        {\n            return new EditorScope(obj);\n        }\n\n        public static LabelWidthScope PushLabelWidth(float labelWidth)\n        {\n            return new LabelWidthScope(labelWidth);\n        }\n\n        public static IndentedRectScope PushIndentedRect(Rect source, int indentLevel)\n        {\n            return new IndentedRectScope(source, indentLevel);\n        }\n\n        public static GuiColorScope PushColor(Color color)\n        {\n            return new GuiColorScope(color);\n        }\n\n        public readonly struct EditorScope : IDisposable\n        {\n            public EditorScope(Object obj)\n            {\n                TargetObjects.Push(obj);\n            }\n\n            public void Dispose()\n            {\n                TargetObjects.Pop();\n            }\n        }\n\n        public readonly struct LabelWidthScope : IDisposable\n        {\n            private readonly float _oldLabelWidth;\n\n            public LabelWidthScope(float labelWidth)\n            {\n                _oldLabelWidth = EditorGUIUtility.labelWidth;\n\n                if (labelWidth > 0)\n                {\n                    EditorGUIUtility.labelWidth = labelWidth;\n                }\n            }\n\n            public void Dispose()\n            {\n                EditorGUIUtility.labelWidth = _oldLabelWidth;\n            }\n        }\n\n        public readonly struct IndentedRectScope : IDisposable\n        {\n            private readonly float _indent;\n\n            public Rect IndentedRect { get; }\n\n            public IndentedRectScope(Rect source, int indentLevel)\n            {\n                _indent = indentLevel * 15;\n\n                IndentedRect = new Rect(source.x + _indent, source.y, source.width - _indent, source.height);\n                EditorGUIUtility.labelWidth -= _indent;\n            }\n\n            public void Dispose()\n            {\n                EditorGUIUtility.labelWidth += _indent;\n            }\n        }\n\n        public readonly struct GuiColorScope : IDisposable\n        {\n            private readonly Color _oldColor;\n\n            public GuiColorScope(Color color)\n            {\n                _oldColor = GUI.color;\n\n                GUI.color = color;\n            }\n\n            public void Dispose()\n            {\n                GUI.color = _oldColor;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriGuiHelper.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 787c857ae9a64fdbb01e6ced9309a09e\ntimeCreated: 1639377094"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriManagedReferenceGui.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    internal static class TriManagedReferenceGui\n    {\n        public static void DrawTypeSelector(Rect rect, TriProperty property)\n        {\n            var typeName = property.ValueType != null\n                ? TriTypeUtilities.GetTypeNiceName(property.ValueType)\n                : \"[None]\";\n            var typeNameContent = new GUIContent(typeName);\n\n            if (EditorGUI.DropdownButton(rect, typeNameContent, FocusType.Passive))\n            {\n                var dropdown = new ReferenceTypeDropDown(property, new AdvancedDropdownState());\n                dropdown.Show(rect);\n\n                if (dropdown.CanHideHeader)\n                {\n                    AdvancedDropdownProxy.SetShowHeader(dropdown, false);\n                }\n\n                Event.current.Use();\n            }\n        }\n\n        private class ReferenceTypeDropDown : AdvancedDropdown\n        {\n            private readonly TriProperty _property;\n\n            public bool CanHideHeader { get; private set; }\n\n            public ReferenceTypeDropDown(TriProperty property, AdvancedDropdownState state) : base(state)\n            {\n                _property = property;\n                minimumSize = new Vector2(0, 120);\n            }\n\n            protected override AdvancedDropdownItem BuildRoot()\n            {\n                var types = TriReflectionUtilities\n                    .AllNonAbstractTypes\n                    .Where(type => !typeof(Object).IsAssignableFrom(type))\n                    .Where(type => _property.FieldType.IsAssignableFrom(type))\n                    .Where(type => type.IsValueType || type.GetConstructor(Type.EmptyTypes) != null)\n                    .ToList();\n\n                var groupByNamespace = types.Count > 20;\n\n                CanHideHeader = !groupByNamespace;\n\n                var root = new ReferenceTypeGroupItem(\"Type\");\n                root.AddChild(new ReferenceTypeItem(null));\n                root.AddSeparator();\n\n                foreach (var type in types)\n                {\n                    IEnumerable<string> namespaceEnumerator = groupByNamespace && type.Namespace != null\n                        ? type.Namespace.Split('.')\n                        : Array.Empty<string>();\n\n                    root.AddTypeChild(type, namespaceEnumerator.GetEnumerator());\n                }\n\n                root.Build();\n\n                return root;\n            }\n\n            protected override void ItemSelected(AdvancedDropdownItem item)\n            {\n                if (!(item is ReferenceTypeItem referenceTypeItem))\n                {\n                    return;\n                }\n\n                if (referenceTypeItem.Type == null)\n                {\n                    _property.SetValue(null);\n                }\n                else\n                {\n                    var instance = Activator.CreateInstance(referenceTypeItem.Type);\n                    _property.SetValue(instance);\n                }\n            }\n\n            private class ReferenceTypeGroupItem : AdvancedDropdownItem\n            {\n                private static readonly Texture2D ScriptIcon = EditorGUIUtility.FindTexture(\"cs Script Icon\");\n\n                private readonly List<ReferenceTypeItem> _childItems = new List<ReferenceTypeItem>();\n\n                private readonly Dictionary<string, ReferenceTypeGroupItem> _childGroups =\n                    new Dictionary<string, ReferenceTypeGroupItem>();\n\n                public ReferenceTypeGroupItem(string name) : base(name)\n                {\n                }\n\n                public void AddTypeChild(Type type, IEnumerator<string> namespaceRemaining)\n                {\n                    if (!namespaceRemaining.MoveNext())\n                    {\n                        _childItems.Add(new ReferenceTypeItem(type, ScriptIcon));\n                        return;\n                    }\n\n                    var ns = namespaceRemaining.Current ?? \"\";\n\n                    if (!_childGroups.TryGetValue(ns, out var child))\n                    {\n                        _childGroups[ns] = child = new ReferenceTypeGroupItem(ns);\n                    }\n\n                    child.AddTypeChild(type, namespaceRemaining);\n                }\n\n                public void Build()\n                {\n                    foreach (var child in _childGroups.Values.OrderBy(it => it.name))\n                    {\n                        AddChild(child);\n\n                        child.Build();\n                    }\n\n                    AddSeparator();\n\n                    foreach (var child in _childItems)\n                    {\n                        AddChild(child);\n                    }\n                }\n            }\n\n            private class ReferenceTypeItem : AdvancedDropdownItem\n            {\n                public ReferenceTypeItem(Type type, Texture2D preview = null)\n                    : base(type != null ? TriTypeUtilities.GetTypeNiceName(type) : \"[None]\")\n                {\n                    Type = type;\n                    icon = preview;\n                }\n\n                public Type Type { get; }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriManagedReferenceGui.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d625706e14d8480a9ab71980d1eb1e48\ntimeCreated: 1638804204"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriReflectionUtilities.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing UnityEditor;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    internal static class TriReflectionUtilities\n    {\n        private static readonly Dictionary<Type, IReadOnlyList<Attribute>> AttributesCache =\n            new Dictionary<Type, IReadOnlyList<Attribute>>();\n\n        private static IReadOnlyList<Assembly> _assemblies;\n        private static IReadOnlyList<Type> _allNonAbstractTypesBackingField;\n\n        public static IReadOnlyList<Assembly> Assemblies\n        {\n            get\n            {\n                if (_assemblies == null)\n                {\n                    _assemblies = AppDomain.CurrentDomain.GetAssemblies();\n                }\n\n                return _assemblies;\n            }\n        }\n\n        public static IReadOnlyList<Type> AllNonAbstractTypes\n        {\n            get\n            {\n                if (_allNonAbstractTypesBackingField == null)\n                {\n                    _allNonAbstractTypesBackingField = Assemblies\n                        .SelectMany(asm =>\n                        {\n                            try\n                            {\n                                return asm.GetTypes();\n                            }\n                            catch (ReflectionTypeLoadException)\n                            {\n                                return Array.Empty<Type>();\n                            }\n                        })\n                        .Where(type => !type.IsAbstract)\n                        .ToList();\n                }\n\n                return _allNonAbstractTypesBackingField;\n            }\n        }\n\n        public static IReadOnlyList<Attribute> GetAttributesCached(Type type)\n        {\n            if (AttributesCache.TryGetValue(type, out var attributes))\n            {\n                return attributes;\n            }\n\n            return AttributesCache[type] = type.GetCustomAttributes().ToList();\n        }\n\n        public static IReadOnlyList<T> GetCustomAttributes<T>(this Assembly asm)\n        {\n            return asm.GetCustomAttributes(typeof(T)).Cast<T>().ToList();\n        }\n\n        public static IReadOnlyList<FieldInfo> GetAllInstanceFieldsInDeclarationOrder(Type type)\n        {\n            const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |\n                                       BindingFlags.Instance | BindingFlags.DeclaredOnly;\n\n            return GetAllMembersInDeclarationOrder(type, it => it.GetFields(flags));\n        }\n\n        public static IReadOnlyList<PropertyInfo> GetAllInstancePropertiesInDeclarationOrder(Type type)\n        {\n            const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |\n                                       BindingFlags.Instance | BindingFlags.DeclaredOnly;\n\n            return GetAllMembersInDeclarationOrder(type, it => it.GetProperties(flags));\n        }\n\n        public static IReadOnlyList<MethodInfo> GetAllInstanceMethodsInDeclarationOrder(Type type)\n        {\n            const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |\n                                       BindingFlags.Instance | BindingFlags.DeclaredOnly;\n\n            return GetAllMembersInDeclarationOrder(type, it => it.GetMethods(flags));\n        }\n\n        public static bool IsArrayOrList(Type type, out Type elementType)\n        {\n            if (type.IsArray)\n            {\n                elementType = type.GetElementType();\n                return true;\n            }\n\n            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))\n            {\n                elementType = type.GetGenericArguments().Single();\n                return true;\n            }\n\n            elementType = null;\n            return false;\n        }\n\n        public static Type GetUnityEditorTypeByFullName(string name)\n        {\n            return GetTypeByFullName(name, typeof(Editor).Assembly);\n        }\n\n        public static Type GetTypeByFullName(string name, Assembly assembly)\n        {\n            return assembly\n                .GetTypes()\n                .Single(it => it.FullName == name);\n        }\n\n        public static bool TryFindTypeByFullName(string name, out Type type)\n        {\n            type = Type.GetType(name);\n            if (type != null)\n            {\n                return true;\n            }\n\n            foreach (var assembly in Assemblies)\n            {\n                type = assembly.GetType(name);\n                if (type != null)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static IReadOnlyList<T> GetAllMembersInDeclarationOrder<T>(\n            Type type, Func<Type, T[]> select)\n            where T : MemberInfo\n        {\n            var result = new List<T>();\n            var typeTree = new Stack<Type>();\n\n            while (type != null)\n            {\n                typeTree.Push(type);\n                type = type.BaseType;\n            }\n\n            foreach (var t in typeTree)\n            {\n                var items = select(t);\n                result.AddRange(items);\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriReflectionUtilities.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 5e3f587ee2e04832bc8cd5cfcd937f32\ntimeCreated: 1638857968"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriTypeUtilities.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    public static class TriTypeUtilities\n    {\n        private static readonly Dictionary<Type, string> TypeNiceNames = new Dictionary<Type, string>();\n\n        public static string GetTypeNiceName(Type type)\n        {\n            if (TypeNiceNames.TryGetValue(type, out var niceName))\n            {\n                return niceName;\n            }\n\n            niceName = type.Name;\n\n            while (type.DeclaringType != null)\n            {\n                niceName = type.DeclaringType.Name + \".\" + niceName;\n\n                type = type.DeclaringType;\n            }\n\n            TypeNiceNames[type] = niceName;\n\n            return niceName;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriTypeUtilities.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: cd64ca1178f24265a0eea33c5dfbb3c9\ntimeCreated: 1690816481"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriUnityInspectorUtilities.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Reflection;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    public class TriUnityInspectorUtilities\n    {\n        private static readonly Dictionary<int, string> StandardArrayElementNames = new Dictionary<int, string>();\n        \n        private static readonly FieldInfo GUIStyleNameBackingField = typeof(GUIStyle)\n            .GetField(\"m_Name\", BindingFlags.Instance | BindingFlags.NonPublic);\n\n        public static bool MustDrawWithUnity(TriProperty property)\n        {\n            if (property.FieldType == typeof(GUIStyle) ||\n                property.FieldType == typeof(RectOffset))\n            {\n                return true;\n            }\n\n            return !property.IsArray && property.TryGetAttribute(out DrawWithUnityAttribute _);\n        }\n\n        public static string GetStandardArrayElementName(TriProperty property)\n        {\n            var index = property.IndexInArray;\n\n            if (!StandardArrayElementNames.TryGetValue(index, out var name))\n            {\n                StandardArrayElementNames[index] = name = $\"Element {index}\";\n            }\n\n            return name;\n        }\n\n        public static bool TryGetSpecialArrayElementName(TriProperty property, out string name)\n        {\n            if (property.FieldType == typeof(GUIStyle) && property.Value is GUIStyle guiStyle)\n            {\n                GUIStyleNameBackingField?.SetValue(guiStyle, null);\n                name = guiStyle.name;\n                return true;\n            }\n\n            if (property.PropertyType == TriPropertyType.Generic &&\n                property.ChildrenProperties.Count > 0 &&\n                property.ChildrenProperties[0] is var firstChild &&\n                firstChild.ValueType == typeof(string) &&\n                firstChild.Value is string firstChildValueStr &&\n                !string.IsNullOrEmpty(firstChildValueStr))\n            {\n                name = firstChildValueStr;\n                return true;\n            }\n\n            name = default;\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriUnityInspectorUtilities.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 239f16a6fc1543b8b131493585c954b3\ntimeCreated: 1668183919"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriUnitySerializationUtilities.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.Inspector.Utilities\n{\n    internal static class TriUnitySerializationUtilities\n    {\n        private static readonly Assembly CoreLibAssembly = typeof(List<>).Assembly;\n        private static readonly Assembly SystemCoreAssembly = typeof(HashSet<>).Assembly;\n        private static readonly Assembly SystemAssembly = typeof(LinkedList<>).Assembly;\n\n        public static bool IsSerializableByUnity(FieldInfo fieldInfo)\n        {\n            if (fieldInfo.IsInitOnly)\n            {\n                return false;\n            }\n\n            if (fieldInfo.GetCustomAttribute<NonSerializedAttribute>() != null ||\n                fieldInfo.GetCustomAttribute<HideInInspector>() != null)\n            {\n                return false;\n            }\n\n            if (fieldInfo.GetCustomAttribute<SerializeReference>() != null)\n            {\n                // if it's a list or array, the base type should be serializable\n                if (fieldInfo.FieldType.IsArray)\n                {\n                    var type = fieldInfo.FieldType.GetElementType();\n                    if (type.IsSerializable || type.IsInterface)\n                        return true;\n                    else\n                        return false;\n                }\n                else if (fieldInfo.FieldType.IsGenericType &&\n                         fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(List<>))\n                {\n                    var type = fieldInfo.FieldType.GenericTypeArguments[0];\n                    if (type.IsSerializable || type.IsInterface)\n                        return true;\n                    else\n                        return false;\n                }\n                else\n                {\n                    return true;\n                }\n            }\n\n            if (fieldInfo.IsPublic || fieldInfo.GetCustomAttribute<SerializeField>() != null)\n            {\n                return IsTypeSerializable(fieldInfo.FieldType);\n            }\n\n            return false;\n        }\n\n        public static bool IsTypeSerializable(Type type, bool allowCollections = true)\n        {\n            if (type == typeof(object) || type.IsInterface)\n            {\n                return false;\n            }\n\n            if (type.IsEnum)\n            {\n                var underlyingType = Enum.GetUnderlyingType(type);\n\n                return underlyingType != typeof(long) && underlyingType != typeof(ulong);\n            }\n\n            if (type.IsPrimitive ||\n                type == typeof(string) ||\n                type == typeof(Vector2) ||\n                type == typeof(Vector2Int) ||\n                type == typeof(Vector3) ||\n                type == typeof(Vector3Int) ||\n                type == typeof(Vector4) ||\n                type == typeof(Color) ||\n                type == typeof(Color32) ||\n                type == typeof(LayerMask) ||\n                type == typeof(Rect) ||\n                type == typeof(RectInt) ||\n                type == typeof(AnimationCurve) ||\n                type == typeof(Bounds) ||\n                type == typeof(BoundsInt) ||\n                type == typeof(Gradient) ||\n                type == typeof(Quaternion))\n            {\n                return true;\n            }\n\n            if (typeof(Object).IsAssignableFrom(type))\n            {\n                return true;\n            }\n\n            if (typeof(Delegate).IsAssignableFrom(type))\n            {\n                return false;\n            }\n\n            if (type.IsArray)\n            {\n                var elementType = type.GetElementType();\n\n                return type.GetArrayRank() == 1 &&\n                       allowCollections &&\n                       IsTypeSerializable(elementType, allowCollections: false);\n            }\n\n            if (type.IsGenericType)\n            {\n                var genericTypeDefinition = type.GetGenericTypeDefinition();\n\n                if (genericTypeDefinition == typeof(List<>))\n                {\n                    var elementType = type.GetGenericArguments()[0];\n\n                    return allowCollections &&\n                           IsTypeSerializable(elementType, allowCollections: false);\n                }\n\n                if (genericTypeDefinition == typeof(Dictionary<,>))\n                {\n                    return false;\n                }\n            }\n\n            if (type.Assembly == CoreLibAssembly ||\n                type.Assembly == SystemAssembly ||\n                type.Assembly == SystemCoreAssembly)\n            {\n                return false;\n            }\n\n            if (type.GetCustomAttribute<SerializableAttribute>() != null)\n            {\n                return true;\n            }\n\n            // any other cases?\n\n            return false;\n        }\n\n        internal static object PopulateUnityDefaultValueForType(Type type)\n        {\n            if (type == typeof(string))\n            {\n                return string.Empty;\n            }\n\n            if (typeof(Object).IsAssignableFrom(type))\n            {\n                return null;\n            }\n\n            if (type.IsEnum)\n            {\n                var values = Enum.GetValues(type);\n                return values.Length > 0 ? values.GetValue(0) : Enum.ToObject(type, 0);\n            }\n\n            if (type.IsValueType)\n            {\n                return Activator.CreateInstance(type);\n            }\n\n            if (type.IsArray && type.GetElementType() is var elementType && elementType != null)\n            {\n                return Array.CreateInstance(elementType, 0);\n            }\n\n            if (type.GetConstructor(Type.EmptyTypes) != null)\n            {\n                return Activator.CreateInstance(type);\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities/TriUnitySerializationUtilities.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: eadfe6520116444e8da02fcd54916d85\ntimeCreated: 1639381952"
  },
  {
    "path": "VirtueSky/Inspector/Editor/Utilities.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 52ef049660d64f2f9b2966acfb8d3447\ntimeCreated: 1638773133"
  },
  {
    "path": "VirtueSky/Inspector/Editor/ValidatorsDrawer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VirtueSky.Inspector.Elements;\nusing UnityEditor;\n\nnamespace VirtueSky.Inspector\n{\n    internal class ValidatorsDrawer : TriCustomDrawer\n    {\n        public override TriElement CreateElementInternal(TriProperty property, TriElement next)\n        {\n            if (!property.HasValidators)\n            {\n                return next;\n            }\n\n            var element = new TriElement();\n            element.AddChild(new TriPropertyValidationResultElement(property));\n            element.AddChild(next);\n            return element;\n        }\n\n        public class TriPropertyValidationResultElement : TriElement\n        {\n            private readonly TriProperty _property;\n            private IReadOnlyList<TriValidationResult> _validationResults;\n\n            public TriPropertyValidationResultElement(TriProperty property)\n            {\n                _property = property;\n            }\n\n            public override float GetHeight(float width)\n            {\n                if (ChildrenCount == 0)\n                {\n                    return -EditorGUIUtility.standardVerticalSpacing;\n                }\n\n                return base.GetHeight(width);\n            }\n\n            public override bool Update()\n            {\n                var dirty = base.Update();\n\n                dirty |= GenerateValidationResults();\n\n                return dirty;\n            }\n\n            private bool GenerateValidationResults()\n            {\n                if (ReferenceEquals(_property.ValidationResults, _validationResults))\n                {\n                    return false;\n                }\n\n                _validationResults = _property.ValidationResults;\n\n                RemoveAllChildren();\n\n                foreach (var result in _validationResults)\n                {\n                    var infoBox = result.FixAction != null\n                        ? new TriInfoBoxElement(result.Message, result.MessageType,\n                            inlineAction: () => ExecuteFix(result.FixAction),\n                            inlineActionContent: result.FixActionContent)\n                        : new TriInfoBoxElement(result.Message, result.MessageType);\n\n                    AddChild(infoBox);\n                }\n\n                return true;\n            }\n\n            private void ExecuteFix(Action fixAction)\n            {\n                _property.ModifyAndRecordForUndo(targetIndex => fixAction?.Invoke());\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/ValidatorsDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 70da4f7e93ab42ffa7b39c465d2d33e1\ntimeCreated: 1652969657"
  },
  {
    "path": "VirtueSky/Inspector/Editor/VirtueSky.Sunflower.Inspector.Editor.asmdef",
    "content": "{\n  \"name\": \"VirtueSky.Sunflower.Inspector.Editor\",\n  \"rootNamespace\": \"\",\n  \"references\": [\n    \"Unity.InternalAPIEditorBridge.013\",\n    \"VirtueSky.Sunflower.Inspector\",\n    \"Virtuesky.Sunflower.Utils\"\n  ],\n  \"includePlatforms\": [\n    \"Editor\"\n  ],\n  \"excludePlatforms\": [],\n  \"allowUnsafeCode\": false,\n  \"overrideReferences\": true,\n  \"precompiledReferences\": [],\n  \"autoReferenced\": true,\n  \"defineConstraints\": [],\n  \"versionDefines\": [],\n  \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor/VirtueSky.Sunflower.Inspector.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: e851236b9ac2b9b4eaaa99506366edea\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawerBase.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public abstract class BuiltinDrawerBase<T> : TriValueDrawer<T>\n    {\n        public sealed override TriElement CreateElement(TriValue<T> propertyValue, TriElement next)\n        {\n            if (propertyValue.Property.TryGetSerializedProperty(out _))\n            {\n                return next;\n            }\n\n            return base.CreateElement(propertyValue, next);\n        }\n\n        public virtual int CompactModeLines => 1;\n        public virtual int WideModeLines => 1;\n\n        public sealed override float GetHeight(float width, TriValue<T> propertyValue, TriElement next)\n        {\n            var lineHeight = EditorGUIUtility.singleLineHeight;\n            var spacing = EditorGUIUtility.standardVerticalSpacing;\n            var lines = EditorGUIUtility.wideMode ? WideModeLines : CompactModeLines;\n            return lineHeight * lines + spacing * (lines - 1);\n        }\n\n        public sealed override void OnGUI(Rect position, TriValue<T> propertyValue, TriElement next)\n        {\n            var value = propertyValue.SmartValue;\n\n            EditorGUI.BeginChangeCheck();\n\n            value = OnValueGUI(position, propertyValue.Property.DisplayNameContent, value);\n\n            if (EditorGUI.EndChangeCheck())\n            {\n                propertyValue.SetValue(value);\n            }\n        }\n\n        protected abstract T OnValueGUI(Rect position, GUIContent label, T value);\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawerBase.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1099ac0317654a238e210dec14c7ea89\ntimeCreated: 1641570232"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawers.cs",
    "content": "﻿using System;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEditor;\nusing UnityEditorInternal;\nusing UnityEngine;\n\n[assembly: RegisterTriValueDrawer(typeof(IntegerDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(LongDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(BooleanDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(FloatDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(StringDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(ColorDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(Color32Drawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(LayerMaskDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(EnumDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(Vector2Drawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(Vector3Drawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(Vector4Drawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(RectDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(AnimationCurveDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(BoundsDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(GradientDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(Vector2IntDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(Vector3IntDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(RectIntDrawer), TriDrawerOrder.Fallback)]\n[assembly: RegisterTriValueDrawer(typeof(BoundsIntDrawer), TriDrawerOrder.Fallback)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class StringDrawer : BuiltinDrawerBase<string>\n    {\n        protected override string OnValueGUI(Rect position, GUIContent label, string value)\n        {\n            return EditorGUI.TextField(position, label, value);\n        }\n    }\n\n    public class BooleanDrawer : BuiltinDrawerBase<bool>\n    {\n        protected override bool OnValueGUI(Rect position, GUIContent label, bool value)\n        {\n            return EditorGUI.Toggle(position, label, value);\n        }\n    }\n\n    public class IntegerDrawer : BuiltinDrawerBase<int>\n    {\n        protected override int OnValueGUI(Rect position, GUIContent label, int value)\n        {\n            return EditorGUI.IntField(position, label, value);\n        }\n    }\n\n    public class LongDrawer : BuiltinDrawerBase<long>\n    {\n        protected override long OnValueGUI(Rect position, GUIContent label, long value)\n        {\n            return EditorGUI.LongField(position, label, value);\n        }\n    }\n\n    public class FloatDrawer : BuiltinDrawerBase<float>\n    {\n        protected override float OnValueGUI(Rect position, GUIContent label, float value)\n        {\n            return EditorGUI.FloatField(position, label, value);\n        }\n    }\n\n    public class ColorDrawer : BuiltinDrawerBase<Color>\n    {\n        protected override Color OnValueGUI(Rect position, GUIContent label, Color value)\n        {\n            return EditorGUI.ColorField(position, label, value);\n        }\n    }\n\n    public class Color32Drawer : BuiltinDrawerBase<Color32>\n    {\n        protected override Color32 OnValueGUI(Rect position, GUIContent label, Color32 value)\n        {\n            return EditorGUI.ColorField(position, label, value);\n        }\n    }\n\n    public class LayerMaskDrawer : BuiltinDrawerBase<LayerMask>\n    {\n        protected override LayerMask OnValueGUI(Rect position, GUIContent label, LayerMask value)\n        {\n            var mask = InternalEditorUtility.LayerMaskToConcatenatedLayersMask(value);\n            var layers = InternalEditorUtility.layers;\n\n            position = EditorGUI.PrefixLabel(position, label);\n            return EditorGUI.MaskField(position, mask, layers);\n        }\n    }\n\n    public class EnumDrawer : BuiltinDrawerBase<Enum>\n    {\n        protected override Enum OnValueGUI(Rect position, GUIContent label, Enum value)\n        {\n            return EditorGUI.EnumPopup(position, label, value);\n        }\n    }\n\n    public class Vector2Drawer : BuiltinDrawerBase<Vector2>\n    {\n        public override int CompactModeLines => 2;\n\n        protected override Vector2 OnValueGUI(Rect position, GUIContent label, Vector2 value)\n        {\n            return EditorGUI.Vector2Field(position, label, value);\n        }\n    }\n\n    public class Vector3Drawer : BuiltinDrawerBase<Vector3>\n    {\n        public override int CompactModeLines => 2;\n\n        protected override Vector3 OnValueGUI(Rect position, GUIContent label, Vector3 value)\n        {\n            return EditorGUI.Vector3Field(position, label, value);\n        }\n    }\n\n    public class Vector4Drawer : BuiltinDrawerBase<Vector4>\n    {\n        public override int CompactModeLines => 2;\n\n        protected override Vector4 OnValueGUI(Rect position, GUIContent label, Vector4 value)\n        {\n            return EditorGUI.Vector4Field(position, label, value);\n        }\n    }\n\n    public class RectDrawer : BuiltinDrawerBase<Rect>\n    {\n        public override int CompactModeLines => 3;\n        public override int WideModeLines => 2;\n\n        protected override Rect OnValueGUI(Rect position, GUIContent label, Rect value)\n        {\n            return EditorGUI.RectField(position, label, value);\n        }\n    }\n\n    public class AnimationCurveDrawer : BuiltinDrawerBase<AnimationCurve>\n    {\n        protected override AnimationCurve OnValueGUI(Rect position, GUIContent label, AnimationCurve value)\n        {\n            return EditorGUI.CurveField(position, label, value);\n        }\n    }\n\n    public class BoundsDrawer : BuiltinDrawerBase<Bounds>\n    {\n        public override int CompactModeLines => 3;\n        public override int WideModeLines => 3;\n\n        protected override Bounds OnValueGUI(Rect position, GUIContent label, Bounds value)\n        {\n            return EditorGUI.BoundsField(position, label, value);\n        }\n    }\n\n    public class GradientDrawer : BuiltinDrawerBase<Gradient>\n    {\n        private static readonly GUIContent NullLabel = new GUIContent(\"Gradient is null\");\n\n        protected override Gradient OnValueGUI(Rect position, GUIContent label, Gradient value)\n        {\n            if (value == null)\n            {\n                EditorGUI.LabelField(position, label, NullLabel);\n                return null;\n            }\n\n            return EditorGUI.GradientField(position, label, value);\n        }\n    }\n\n    public class Vector2IntDrawer : BuiltinDrawerBase<Vector2Int>\n    {\n        public override int CompactModeLines => 2;\n\n        protected override Vector2Int OnValueGUI(Rect position, GUIContent label, Vector2Int value)\n        {\n            return EditorGUI.Vector2IntField(position, label, value);\n        }\n    }\n\n    public class Vector3IntDrawer : BuiltinDrawerBase<Vector3Int>\n    {\n        public override int CompactModeLines => 2;\n\n        protected override Vector3Int OnValueGUI(Rect position, GUIContent label, Vector3Int value)\n        {\n            return EditorGUI.Vector3IntField(position, label, value);\n        }\n    }\n\n    public class RectIntDrawer : BuiltinDrawerBase<RectInt>\n    {\n        public override int CompactModeLines => 3;\n        public override int WideModeLines => 2;\n\n        protected override RectInt OnValueGUI(Rect position, GUIContent label, RectInt value)\n        {\n            return EditorGUI.RectIntField(position, label, value);\n        }\n    }\n\n    public class BoundsIntDrawer : BuiltinDrawerBase<BoundsInt>\n    {\n        public override int CompactModeLines => 3;\n        public override int WideModeLines => 3;\n\n        protected override BoundsInt OnValueGUI(Rect position, GUIContent label, BoundsInt value)\n        {\n            return EditorGUI.BoundsIntField(position, label, value);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/BuiltinDrawers.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e7795a3fa9734e729f1567c86c4926c5\ntimeCreated: 1639317854"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/ButtonDrawer.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(ButtonDrawer), TriDrawerOrder.Drawer)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class ButtonDrawer : TriAttributeDrawer<ButtonAttribute>\n    {\n        private ValueResolver<string> _nameResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            var isValidMethod = propertyDefinition.TryGetMemberInfo(out var memberInfo) && memberInfo is MethodInfo;\n            if (!isValidMethod)\n            {\n                return \"[Button] valid only on methods\";\n            }\n\n            _nameResolver = ValueResolver.ResolveString(propertyDefinition, Attribute.Name);\n            if (_nameResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new TriButtonElement(property, Attribute, _nameResolver);\n        }\n\n        private class TriButtonElement : TriHeaderGroupBaseElement\n        {\n            private readonly TriProperty _property;\n            private readonly ButtonAttribute _attribute;\n            private readonly ValueResolver<string> _nameResolver;\n            private readonly object[] _invocationArgs;\n\n            public TriButtonElement(TriProperty property, ButtonAttribute attribute,\n                ValueResolver<string> nameResolver)\n            {\n                _property = property;\n                _attribute = attribute;\n                _nameResolver = nameResolver;\n\n                var mi = property.TryGetMemberInfo(out var memberInfo)\n                    ? (MethodInfo) memberInfo\n                    : throw new Exception(\"TriButtonElement requires MethodInfo\");\n\n                var parameters = mi.GetParameters();\n\n                _invocationArgs = new object[parameters.Length];\n\n                for (var i = 0; i < parameters.Length; i++)\n                {\n                    var pIndex = i;\n                    var pInfo = parameters[pIndex];\n\n                    if (pInfo.HasDefaultValue)\n                    {\n                        _invocationArgs[pIndex] = pInfo.DefaultValue;\n                    }\n\n                    var pTriDefinition = TriPropertyDefinition.CreateForGetterSetter(\n                        pIndex, pInfo.Name, pInfo.ParameterType,\n                        ((self, targetIndex) => _invocationArgs[pIndex]),\n                        ((self, targetIndex, value) => _invocationArgs[pIndex] = value));\n\n                    var pTriProperty = new TriProperty(_property.PropertyTree, _property, pTriDefinition, null);\n\n                    AddChild(new TriPropertyElement(pTriProperty));\n                }\n            }\n\n            protected override float GetHeaderHeight(float width)\n            {\n                return GetButtonHeight();\n            }\n\n            protected override void DrawHeader(Rect position)\n            {\n                if (_invocationArgs.Length > 0)\n                {\n                    TriEditorGUI.DrawBox(position, TriEditorStyles.TabOnlyOne);\n                }\n\n                var name = _nameResolver.GetValue(_property);\n\n                if (string.IsNullOrEmpty(name))\n                {\n                    name = _property.DisplayName;\n                }\n\n                if (string.IsNullOrEmpty(name))\n                {\n                    name = _property.RawName;\n                }\n\n                var buttonRect = new Rect(position)\n                {\n                    height = GetButtonHeight(),\n                };\n\n                if (GUI.Button(buttonRect, name))\n                {\n                    InvokeButton(_property, _invocationArgs);\n                }\n            }\n\n            private float GetButtonHeight()\n            {\n                return _attribute.ButtonSize != 0\n                    ? _attribute.ButtonSize\n                    : EditorGUIUtility.singleLineHeight;\n            }\n        }\n\n        private static void InvokeButton(TriProperty property, object[] parameters)\n        {\n            if (property.TryGetMemberInfo(out var memberInfo) && memberInfo is MethodInfo methodInfo)\n            {\n                property.ModifyAndRecordForUndo(targetIndex =>\n                {\n                    try\n                    {\n                        var parentValue = property.Parent.GetValue(targetIndex);\n                        methodInfo.Invoke(parentValue, parameters);\n                    }\n                    catch (Exception e)\n                    {\n                        Debug.LogException(e);\n                    }\n                });\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/ButtonDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 72993eec72494727a60c1ddf2f29abab\ntimeCreated: 1642527717"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/CustomBuiltInDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Editors;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.Utilities;\nusing VirtueSky.InspectorUnityInternalBridge;\n\n[assembly: RegisterTriValueDrawer(typeof(CustomBuiltInDrawer), TriDrawerOrder.Fallback - 999)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class CustomBuiltInDrawer : TriValueDrawer<object>\n    {\n        public override TriElement CreateElement(TriValue<object> propertyValue, TriElement next)\n        {\n            var property = propertyValue.Property;\n\n            if (property.TryGetSerializedProperty(out var serializedProperty))\n            {\n                var handler = ScriptAttributeUtilityProxy.GetHandler(serializedProperty);\n\n                var drawWithHandler = handler.hasPropertyDrawer ||\n                                      property.PropertyType == TriPropertyType.Primitive ||\n                                      TriUnityInspectorUtilities.MustDrawWithUnity(property);\n\n                if (drawWithHandler)\n                {\n                    if (property.TryGetAttribute(out DrawWithUnityAttribute withUnityAttribute) &&\n                        withUnityAttribute.WithUiToolkit)\n                    {\n                        handler.SetPreferredLabel(property.DisplayName);\n\n                        var visualElement = handler.CreatePropertyGUI(serializedProperty);\n\n                        if (visualElement != null &&\n                            TriEditorCore.UiElementsRoots.TryGetValue(property.PropertyTree, out var rootElement))\n                        {\n                            return new TriUiToolkitPropertyElement(property, serializedProperty,\n                                visualElement, rootElement);\n                        }\n                    }\n\n                    return new TriBuiltInPropertyElement(property, serializedProperty, handler);\n                }\n            }\n\n            return base.CreateElement(propertyValue, next);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/CustomBuiltInDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 01398997ba14482caf7fd7c566774973\ntimeCreated: 1670393704"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/DisplayAsStringDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(DisplayAsStringDrawer), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class DisplayAsStringDrawer : TriAttributeDrawer<DisplayAsStringAttribute>\n    {\n        public override float GetHeight(float width, TriProperty property, TriElement next)\n        {\n            return EditorGUIUtility.singleLineHeight;\n        }\n\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            var value = property.Value;\n            var text = value != null ? value.ToString() : \"Null\";\n\n            var controlId = GUIUtility.GetControlID(FocusType.Passive);\n            position = EditorGUI.PrefixLabel(position, controlId, property.DisplayNameContent);\n            GUI.Label(position, text);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/DisplayAsStringDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 094b0ef0486f4f2faf35dba6da11e6b9\ntimeCreated: 1678604678"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/DropdownDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.Resolvers;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(DropdownDrawer<>), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class DropdownDrawer<T> : TriAttributeDrawer<DropdownAttribute>\n    {\n        private DropdownValuesResolver<T> _valuesResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            _valuesResolver = DropdownValuesResolver<T>.Resolve(propertyDefinition, Attribute.Values);\n\n            if (_valuesResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new TriDropdownElement(property, _valuesResolver.GetDropdownItems);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/DropdownDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 355fb8aedd1f4aca846a8bbf96558a5d\ntimeCreated: 1656941791"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/EnumToggleButtonsDrawer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(EnumToggleButtonsDrawer), TriDrawerOrder.Drawer,\n    ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class EnumToggleButtonsDrawer : TriAttributeDrawer<EnumToggleButtonsAttribute>\n    {\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (!propertyDefinition.FieldType.IsEnum)\n            {\n                return \"EnumToggleButtons attribute can be used only on enums\";\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new EnumToggleButtonsElement(property);\n        }\n\n        private sealed class EnumToggleButtonsElement : TriElement\n        {\n            private readonly TriProperty _property;\n            private readonly List<EnumEntry> _enumValues;\n            private readonly bool _isFlags;\n\n            public EnumToggleButtonsElement(TriProperty property)\n            {\n                _property = property;\n                _enumValues = Enum.GetNames(property.FieldType)\n                    .Zip(Enum.GetValues(property.FieldType).OfType<Enum>(), (name, value) => new EnumEntry\n                    {\n                        name = name,\n                        value = value,\n                        displayName = ObjectNames.NicifyVariableName(name),\n                    })\n                    .ToList();\n                _isFlags = property.FieldType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;\n\n                var enumFields = property.FieldType.GetFields(BindingFlags.Static | BindingFlags.Public);\n\n                foreach (var enumValue in _enumValues)\n                {\n                    var enumField = Array.Find(enumFields, it => it.Name == enumValue.name);\n                    var inspectorNameAttr = enumField?.GetCustomAttribute<InspectorNameAttribute>();\n                    if (inspectorNameAttr != null)\n                    {\n                        enumValue.displayName = inspectorNameAttr.displayName;\n                    }\n                }\n\n                _enumValues.Sort(new DeclarationOrderComparer(enumFields));\n            }\n\n            public override float GetHeight(float width)\n            {\n                return EditorGUIUtility.singleLineHeight;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                var value = _property.TryGetSerializedProperty(out var serializedProperty)\n                    ? (Enum) Enum.ToObject(_property.FieldType, serializedProperty.longValue)\n                    : (Enum) _property.Value;\n\n                var controlId = GUIUtility.GetControlID(FocusType.Passive);\n                position = EditorGUI.PrefixLabel(position, controlId, _property.DisplayNameContent);\n\n                for (var i = 0; i < _enumValues.Count; i++)\n                {\n                    var itemRect = SplitRectWidth(position, _enumValues.Count, i);\n                    var itemStyle = GetButtonStyle(_enumValues.Count, i);\n                    var itemDisplayName = _enumValues[i].displayName;\n                    var itemValue = _enumValues[i].value;\n\n                    var oldSelected = value != null && (_isFlags ? value.HasFlag(itemValue) : value.Equals(itemValue));\n                    var newSelected = GUI.Toggle(itemRect, oldSelected, itemDisplayName, itemStyle);\n\n                    if (oldSelected != newSelected)\n                    {\n                        if (_isFlags)\n                        {\n                            var newValue = newSelected\n                                ? (Convert.ToInt64(value) | Convert.ToInt64(itemValue))\n                                : (Convert.ToInt64(value) & ~Convert.ToInt64(itemValue));\n\n                            _property.SetValue((Enum) Enum.ToObject(_property.FieldType, newValue));\n                        }\n                        else\n                        {\n                            _property.SetValue(itemValue);\n                        }\n                    }\n                }\n            }\n\n            private static GUIStyle GetButtonStyle(int total, int current)\n            {\n                if (total <= 1)\n                {\n                    return EditorStyles.miniButton;\n                }\n\n                if (current == 0)\n                {\n                    return EditorStyles.miniButtonLeft;\n                }\n\n                if (current == total - 1)\n                {\n                    return EditorStyles.miniButtonRight;\n                }\n\n                return EditorStyles.miniButtonMid;\n            }\n\n            private static Rect SplitRectWidth(Rect rect, int total, int current)\n            {\n                if (total == 0)\n                {\n                    return rect;\n                }\n\n                rect.width /= total;\n                rect.x += rect.width * current;\n                return rect;\n            }\n\n            private class EnumEntry\n            {\n                public string name;\n                public string displayName;\n                public Enum value;\n            }\n\n            private class DeclarationOrderComparer : IComparer<EnumEntry>\n            {\n                private readonly FieldInfo[] _fields;\n\n                public DeclarationOrderComparer(FieldInfo[] fields)\n                {\n                    _fields = fields;\n                }\n\n                public int Compare(EnumEntry x, EnumEntry y)\n                {\n                    var orderX = Array.FindIndex(_fields, it => it.Name == x.name);\n                    var orderY = Array.FindIndex(_fields, it => it.Name == y.name);\n                    return orderX.CompareTo(orderY);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/EnumToggleButtonsDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4f78353120e744dead6caed9c9891e25\ntimeCreated: 1653817544"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/GUIColorDrawer.cs",
    "content": "﻿using JetBrains.Annotations;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Resolvers;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(GUIColorDrawer), TriDrawerOrder.Decorator)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class GUIColorDrawer : TriAttributeDrawer<GUIColorAttribute>\n    {\n        [CanBeNull] private ValueResolver<Color> _colorResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (!string.IsNullOrEmpty(Attribute.GetColor))\n            {\n                _colorResolver = ValueResolver.Resolve<Color>(propertyDefinition, Attribute.GetColor);\n            }\n\n            if (_colorResolver != null && _colorResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            var oldColor = GUI.color;\n            var newColor = _colorResolver?.GetValue(property, Color.white) ?? Attribute.Color;\n\n            GUI.color = newColor;\n            GUI.contentColor = newColor;\n\n            next.OnGUI(position);\n\n            GUI.color = oldColor;\n            GUI.contentColor = oldColor;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/GUIColorDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 3e34331cbcd3451cb18c9cc11c43f7b3\ntimeCreated: 1638943578"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/IndentDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(IndentDrawer), TriDrawerOrder.Decorator)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class IndentDrawer : TriAttributeDrawer<IndentAttribute>\n    {\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            using (var indentedRectScope = TriGuiHelper.PushIndentedRect(position, Attribute.Indent))\n            {\n                next.OnGUI(indentedRectScope.IndentedRect);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/IndentDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 53bdb27623d2437a9af368e1342d9176\ntimeCreated: 1638947263"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/InlineEditorDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\n[assembly: RegisterTriAttributeDrawer(typeof(InlineEditorDrawer), TriDrawerOrder.Decorator,\n    ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class InlineEditorDrawer : TriAttributeDrawer<InlineEditorAttribute>\n    {\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (!typeof(Object).IsAssignableFrom(propertyDefinition.FieldType))\n            {\n                return \"[InlineEditor] valid only on Object fields\";\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            var element = new TriBoxGroupElement(new TriBoxGroupElement.Props\n            {\n                titleMode = TriBoxGroupElement.TitleMode.Hidden,\n            });\n            element.AddChild(new ObjectReferenceFoldoutDrawerElement(property));\n            element.AddChild(new InlineEditorElement(property, new InlineEditorElement.Props\n            {\n                mode = Attribute.Mode,\n                previewHeight = Attribute.PreviewHeight,\n            }));\n            return element;\n        }\n\n        private class ObjectReferenceFoldoutDrawerElement : TriElement\n        {\n            private readonly TriProperty _property;\n\n            public ObjectReferenceFoldoutDrawerElement(TriProperty property)\n            {\n                _property = property;\n            }\n\n            public override float GetHeight(float width)\n            {\n                return EditorGUIUtility.singleLineHeight;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                var prefixRect = new Rect(position)\n                {\n                    height = EditorGUIUtility.singleLineHeight,\n                    xMax = position.xMin + EditorGUIUtility.labelWidth,\n                };\n                var pickerRect = new Rect(position)\n                {\n                    height = EditorGUIUtility.singleLineHeight,\n                    xMin = prefixRect.xMax,\n                };\n\n                TriEditorGUI.Foldout(prefixRect, _property);\n\n                EditorGUI.BeginChangeCheck();\n\n                var allowSceneObjects = _property.PropertyTree.TargetIsPersistent == false;\n\n                var value = (Object) _property.Value;\n                value = EditorGUI.ObjectField(pickerRect, GUIContent.none, value,\n                    _property.FieldType, allowSceneObjects);\n\n                if (EditorGUI.EndChangeCheck())\n                {\n                    _property.SetValue(value);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/InlineEditorDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 088c34bc4fc448b4aac18ed9bf4f9bc6\ntimeCreated: 1641657562"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/LabelWidthDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(LabelWidthDrawer), TriDrawerOrder.Decorator)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class LabelWidthDrawer : TriAttributeDrawer<LabelWidthAttribute>\n    {\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            var oldLabelWidth = EditorGUIUtility.labelWidth;\n\n            EditorGUIUtility.labelWidth = Attribute.Width;\n            next.OnGUI(position);\n            EditorGUIUtility.labelWidth = oldLabelWidth;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/LabelWidthDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d7bb028f84224ec5817b1c807ca5db86\ntimeCreated: 1638948103"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/ObjectReferenceDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriValueDrawer(typeof(ObjectReferenceDrawer), TriDrawerOrder.Fallback)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class ObjectReferenceDrawer : TriValueDrawer<Object>\n    {\n        public override TriElement CreateElement(TriValue<Object> value, TriElement next)\n        {\n            if (value.Property.IsRootProperty || value.Property.TryGetSerializedProperty(out _))\n            {\n                return next;\n            }\n\n            return new ObjectReferenceDrawerElement(value);\n        }\n\n        private class ObjectReferenceDrawerElement : TriElement\n        {\n            private TriValue<Object> _propertyValue;\n            private readonly bool _allowSceneObjects;\n\n            public ObjectReferenceDrawerElement(TriValue<Object> propertyValue)\n            {\n                _propertyValue = propertyValue;\n                _allowSceneObjects = propertyValue.Property.PropertyTree.TargetIsPersistent == false;\n            }\n\n            public override float GetHeight(float width)\n            {\n                return EditorGUIUtility.singleLineHeight;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                var value = _propertyValue.SmartValue;\n\n                EditorGUI.BeginChangeCheck();\n\n                value = EditorGUI.ObjectField(position, _propertyValue.Property.DisplayNameContent, value,\n                    _propertyValue.Property.FieldType, _allowSceneObjects);\n\n                if (EditorGUI.EndChangeCheck())\n                {\n                    _propertyValue.SetValue(value);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/ObjectReferenceDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 95268b41deb942b8882969bf23911eaf\ntimeCreated: 1641571162"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/OnValueChangedDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Resolvers;\n\n[assembly: RegisterTriAttributeDrawer(typeof(OnValueChangedDrawer), TriDrawerOrder.System)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class OnValueChangedDrawer : TriAttributeDrawer<OnValueChangedAttribute>\n    {\n        private ActionResolver _actionResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            base.Initialize(propertyDefinition);\n\n            _actionResolver = ActionResolver.Resolve(propertyDefinition, Attribute.Method);\n            if (_actionResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new OnValueChangedListenerElement(property, next, _actionResolver);\n        }\n\n        private class OnValueChangedListenerElement : TriElement\n        {\n            private readonly TriProperty _property;\n            private readonly ActionResolver _actionResolver;\n\n            public OnValueChangedListenerElement(TriProperty property, TriElement next, ActionResolver actionResolver)\n            {\n                _property = property;\n                _actionResolver = actionResolver;\n\n                AddChild(next);\n            }\n\n            protected override void OnAttachToPanel()\n            {\n                base.OnAttachToPanel();\n\n                _property.ValueChanged += OnValueChanged;\n                _property.ChildValueChanged += OnValueChanged;\n            }\n\n            protected override void OnDetachFromPanel()\n            {\n                _property.ChildValueChanged -= OnValueChanged;\n                _property.ValueChanged -= OnValueChanged;\n\n                base.OnDetachFromPanel();\n            }\n\n            private void OnValueChanged(TriProperty obj)\n            {\n                _property.PropertyTree.ApplyChanges();\n                _actionResolver.InvokeForAllTargets(_property);\n                _property.PropertyTree.Update();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/OnValueChangedDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 16bb69c0bfa84c69b1cd04863fdd1570\ntimeCreated: 1654159943"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/PreviewMeshDrawer.cs",
    "content": "using System;\nusing System.Linq;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\n[assembly: RegisterTriAttributeDrawer(typeof(PreviewMeshDrawer), TriDrawerOrder.Decorator,\n    ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class PreviewMeshDrawer : TriAttributeDrawer<PreviewMeshAttribute>\n    {\n        private class PreviewMeshPicker : TriElement\n        {\n            private readonly TriProperty _property;\n            private readonly bool _useFoldout;\n\n            public PreviewMeshPicker(TriProperty property, bool useFoldout)\n            {\n                _property = property;\n                _useFoldout = useFoldout;\n            }\n\n            public override float GetHeight(float width)\n            {\n                return EditorGUIUtility.singleLineHeight;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                var pickerRect = position;\n                GUIContent label = new(_property.DisplayName);\n\n                if (_useFoldout)\n                {\n                    var prefixRect = new Rect(position)\n                    {\n                        height = EditorGUIUtility.singleLineHeight,\n                        xMax = position.xMin + EditorGUIUtility.labelWidth,\n                    };\n                    pickerRect = new Rect(position)\n                    {\n                        height = EditorGUIUtility.singleLineHeight,\n                        xMin = prefixRect.xMax,\n                    };\n\n                    TriEditorGUI.Foldout(prefixRect, _property);\n                    label = GUIContent.none;\n                }\n\n                EditorGUI.BeginChangeCheck();\n                Object obj = _property.Value as Object;\n                var asset = EditorGUI.ObjectField(pickerRect, label, obj, typeof(GameObject), true);\n                if (EditorGUI.EndChangeCheck())\n                {\n                    _property.SetValue(asset);\n                }\n            }\n        }\n\n        private class PreviewMesh : TriElement\n        {\n            private readonly int _height;\n            private readonly int _width;\n            private readonly TriProperty _property;\n            private readonly bool _useFoldout;\n            private readonly PreviewMeshRotationMethod _rotationMethod;\n\n            private PreviewRenderUtility _previewUtility;\n            private static Material _mat;\n\n            private Material GetMat\n            {\n                get\n                {\n                    if (_mat == null)\n                    {\n                        var shaderNames = new[]\n                        {\n                            \"Universal Render Pipeline/Lit\",\n                            \"Standard\",\n                            \"Legacy Shaders/Diffuse\",\n                        };\n\n                        var shader = shaderNames.Select(name => Shader.Find(name)).First(shader => shader != null);\n\n                        _mat = new Material(shader)\n                        {\n                            hideFlags = HideFlags.HideAndDontSave,\n                            color = new Color(0.4f, 0.7f, 0.4f),\n                        };\n                    }\n\n                    return _mat;\n                }\n            }\n\n            private readonly float _c_ROTATION_SENSITIVITY = -0.5f;\n            private readonly float _c_ZOOM_SENSITIVITY = 0.1f;\n            private readonly float _c_ZOOM_SENSITIVITY_MIN = 2f;\n            private readonly float _c_ZOOM_SENSITIVITY_MAX = 10f;\n            private readonly float _c_MIN_WIDTH = 50f;\n            private readonly float _c_DEFAULT_CAMERA_DISTANCE = 4f;\n\n            private Quaternion _previewQuaternion;\n            private Mesh _sharedMesh;\n            private float _distance;\n\n            private Vector2 _previewDir = new(-20f, 0f);\n\n            #region Initialization\n\n            public PreviewMesh(TriProperty property, int size, int width, bool useFoldout,\n                PreviewMeshRotationMethod rotationMethod)\n            {\n                _property = property;\n                _height = size;\n                _width = width;\n                _useFoldout = useFoldout;\n                _rotationMethod = rotationMethod;\n            }\n\n            protected override void OnAttachToPanel()\n            {\n                _previewUtility = new();\n                _property.ValueChanged += OnValueChanged;\n\n                // Setup lights\n                _previewUtility.lights[0].intensity = 1.3f;\n                _previewUtility.lights[0].transform.rotation = Quaternion.Euler(40f, 40f, 0);\n                _previewUtility.lights[1].intensity = 1.3f;\n\n                // Setup camera\n                _previewUtility.cameraFieldOfView = 30f;\n                _previewUtility.camera.nearClipPlane = 0.1f;\n                _previewUtility.camera.farClipPlane = 100f;\n                _previewUtility.camera.backgroundColor = Color.black;\n                _previewUtility.camera.clearFlags = CameraClearFlags.Color;\n\n                base.OnAttachToPanel();\n\n                GetMeshObject();\n            }\n\n            protected override void OnDetachFromPanel()\n            {\n                _previewUtility.Cleanup();\n                _previewUtility = null;\n\n                _property.ValueChanged -= OnValueChanged;\n\n                base.OnDetachFromPanel();\n            }\n\n            private void OnValueChanged(TriProperty property)\n            {\n                GetMeshObject();\n            }\n\n            public override float GetHeight(float width)\n            {\n                if (_sharedMesh == null)\n                {\n                    return 0f;\n                }\n\n                if (!_useFoldout || _property.IsExpanded)\n                {\n                    return _height;\n                }\n\n                return 0f;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                if (_sharedMesh == null)\n                {\n                    return;\n                }\n\n                float currentWidth = _width == -1 ? (int)position.width : _width;\n                currentWidth = Math.Max(currentWidth, _c_MIN_WIDTH);\n\n                if (position.height == 0f)\n                {\n                    return;\n                }\n\n                position = new Rect(position.x, position.y, currentWidth, _height);\n                _previewUtility.BeginPreview(position, GUIStyle.none);\n                _previewUtility.DrawMesh(_sharedMesh, Matrix4x4.TRS(Vector3.zero, _previewQuaternion, Vector3.one),\n                    GetMat, 0);\n                _previewUtility.camera.Render();\n\n                Texture result = _previewUtility.EndPreview();\n\n                if (result)\n                {\n                    GUI.DrawTexture(position, result, ScaleMode.ScaleToFit, false);\n                }\n\n                if (position.Contains(Event.current.mousePosition))\n                {\n                    HandleMouseEvent(Event.current);\n                }\n            }\n\n            #endregion\n\n\n            #region Helper Function\n\n            private void GetMeshObject()\n            {\n                var obj = _property.Value as Object;\n\n                if (obj == null)\n                {\n                    _sharedMesh = null;\n                    return;\n                }\n\n                _previewQuaternion = Quaternion.Euler(_previewDir);\n                _distance = _c_DEFAULT_CAMERA_DISTANCE;\n\n                // Draw supported types\n                if (obj is Mesh mesh)\n                {\n                    _sharedMesh = mesh;\n                }\n                else if (obj is GameObject go)\n                {\n                    var mf = go.GetComponentInChildren<MeshFilter>();\n                    if (mf != null)\n                    {\n                        _sharedMesh = mf.sharedMesh;\n                    }\n                    else\n                    {\n                        Debug.Log(\"No MeshFilter found on GameObject.\");\n                    }\n                }\n\n                if (_sharedMesh != null)\n                {\n                    UpdatePreviewCamera();\n                }\n            }\n\n            private void UpdatePreviewCamera()\n            {\n                var bounds = _sharedMesh.bounds;\n\n                // fallback bounds\n                if (bounds.size == Vector3.zero)\n                {\n                    bounds = new Bounds(Vector3.zero, Vector3.one);\n                }\n\n                var magnitude = bounds.extents.magnitude;\n                _previewUtility.camera.transform.position = bounds.center + Vector3.back * (magnitude * _distance);\n                _previewUtility.camera.transform.LookAt(bounds.center);\n            }\n\n            private void HandleMouseEvent(Event mouseEvent)\n            {\n                var shift = mouseEvent.shift;\n\n                switch (mouseEvent.type)\n                {\n                    case EventType.MouseDrag:\n                        var cameraMovement = mouseEvent.delta * _c_ROTATION_SENSITIVITY;\n                        HandlePreviewCameraRotation(cameraMovement);\n                        mouseEvent.Use();\n                        break;\n\n                    case EventType.ScrollWheel:\n                        _distance = Mathf.Clamp(_distance + mouseEvent.delta.x * _c_ZOOM_SENSITIVITY,\n                            _c_ZOOM_SENSITIVITY_MIN, _c_ZOOM_SENSITIVITY_MAX);\n                        if (shift)\n                        {\n                            UpdatePreviewCamera();\n                            mouseEvent.Use();\n                        }\n\n                        break;\n\n                    default:\n                        return;\n                }\n            }\n\n            private void HandlePreviewCameraRotation(Vector2 movement)\n            {\n                float pitch = movement.y;\n                float yaw = movement.x;\n\n                switch (_rotationMethod)\n                {\n                    case PreviewMeshRotationMethod.Clamped:\n                        _previewDir.x = Mathf.Clamp(pitch + _previewDir.x, -90f, 90);\n                        _previewDir.y += yaw;\n                        _previewQuaternion = Quaternion.Euler(_previewDir.x, 0, 0) *\n                                             Quaternion.Euler(0, _previewDir.y, 0);\n                        break;\n                    case PreviewMeshRotationMethod.Freeform:\n                        _previewQuaternion = Quaternion.Euler(pitch, yaw, 0) * _previewQuaternion;\n                        break;\n                }\n\n                _previewQuaternion = Quaternion.Normalize(_previewQuaternion);\n            }\n\n            #endregion\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            var root = new TriBoxGroupElement(new TriBoxGroupElement.Props\n            {\n                titleMode = TriBoxGroupElement.TitleMode.Hidden,\n            });\n            root.AddChild(new PreviewMeshPicker(property, Attribute.UseFoldout));\n            root.AddChild(new PreviewMesh(property, Attribute.Height, Attribute.Width, Attribute.UseFoldout,\n                Attribute.RotationMethod));\n            return root;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/PreviewMeshDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2f834cedcca8433e99c9f51aca35c8ea\ntimeCreated: 1758476267"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/PropertySpaceDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(PropertySpaceDrawer), TriDrawerOrder.Inspector)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class PropertySpaceDrawer : TriAttributeDrawer<PropertySpaceAttribute>\n    {\n        public override float GetHeight(float width, TriProperty property, TriElement next)\n        {\n            var totalSpace = Attribute.SpaceBefore + Attribute.SpaceAfter;\n\n            return next.GetHeight(width) + totalSpace;\n        }\n\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            var contentPosition = new Rect(position)\n            {\n                yMin = position.yMin + Attribute.SpaceBefore,\n                yMax = position.yMax - Attribute.SpaceAfter,\n            };\n\n            next.OnGUI(contentPosition);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/PropertySpaceDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d703a4146e75487aa57e22f375b04c32\ntimeCreated: 1638942558"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/SceneDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(SceneDrawer), TriDrawerOrder.Decorator, ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class SceneDrawer : TriAttributeDrawer<SceneAttribute>\n    {\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            var type = propertyDefinition.FieldType;\n            if (type != typeof(string))\n            {\n                return \"Scene attribute can only be used on field with string type\";\n            }\n\n            return base.Initialize(propertyDefinition);\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new SceneElement(property);\n        }\n\n        private class SceneElement : TriElement\n        {\n            private readonly TriProperty _property;\n\n            private SceneAsset _sceneAsset;\n\n            public SceneElement(TriProperty property)\n            {\n                _property = property;\n            }\n\n            protected override void OnAttachToPanel()\n            {\n                base.OnAttachToPanel();\n\n                _property.ValueChanged += OnValueChanged;\n\n                RefreshSceneAsset();\n            }\n\n            protected override void OnDetachFromPanel()\n            {\n                _property.ValueChanged -= OnValueChanged;\n\n                base.OnDetachFromPanel();\n            }\n\n            public override float GetHeight(float width)\n            {\n                return EditorGUIUtility.singleLineHeight;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                EditorGUI.BeginChangeCheck();\n\n                var asset = EditorGUI.ObjectField(position, _property.DisplayName, _sceneAsset,\n                    typeof(SceneAsset), false);\n\n                if (EditorGUI.EndChangeCheck())\n                {\n                    var path = AssetDatabase.GetAssetPath(asset);\n                    _property.SetValue(path);\n                }\n            }\n\n            private void OnValueChanged(TriProperty property)\n            {\n                RefreshSceneAsset();\n            }\n\n            private void RefreshSceneAsset()\n            {\n                _sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(_property.Value as string);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/SceneDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 47b6083a040749429c1f3371f0413847\ntimeCreated: 1657956568"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/ShowDrawerChainDrawer.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Text;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Elements;\n\n[assembly: RegisterTriAttributeDrawer(typeof(ShowDrawerChainDrawer), TriDrawerOrder.System)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class ShowDrawerChainDrawer : TriAttributeDrawer<ShowDrawerChainAttribute>\n    {\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new TriDrawerChainInfoElement(property.AllDrawers, next);\n        }\n    }\n\n    public class TriDrawerChainInfoElement : TriElement\n    {\n        public TriDrawerChainInfoElement(IReadOnlyList<TriCustomDrawer> drawers, TriElement next)\n        {\n            var info = new StringBuilder();\n\n            info.Append(\"Drawer Chain:\");\n\n            for (var i = 0; i < drawers.Count; i++)\n            {\n                var drawer = drawers[i];\n                info.AppendLine();\n                info.Append(i).Append(\": \").Append(drawer.GetType().Name);\n            }\n\n            AddChild(new TriInfoBoxElement(info.ToString()));\n            AddChild(next);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/ShowDrawerChainDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d473213c669247e48e0059471d0b6d2c\ntimeCreated: 1639215046"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/TableListDrawer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.Utilities;\nusing VirtueSky.InspectorUnityInternalBridge;\nusing UnityEditor;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEditorInternal;\nusing UnityEngine;\n\n#if UNITY_6000_2_OR_NEWER\nusing TreeView = UnityEditor.IMGUI.Controls.TreeView<int>;\nusing TreeViewState = UnityEditor.IMGUI.Controls.TreeViewState<int>;\nusing TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem<int>;\n#endif\n\n[assembly: RegisterTriAttributeDrawer(typeof(TableListDrawer), TriDrawerOrder.Drawer)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class TableListDrawer : TriAttributeDrawer<TableListAttribute>\n    {\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (!propertyDefinition.IsArray)\n            {\n                return \"[TableList] valid only on lists\";\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriElement CreateElement(TriProperty property, TriElement next)\n        {\n            return new TableElement(property);\n        }\n\n        private class TableElement : TriListElement\n        {\n            private const float FooterExtraSpace = 4;\n\n            private readonly TriProperty _property;\n            private readonly TableMultiColumnTreeView _treeView;\n            private readonly bool _alwaysExpanded;\n\n            private bool _reloadRequired;\n            private bool _heightDirty;\n            private bool _isExpanded;\n            private int _arraySize;\n\n            public TableElement(TriProperty property) : base(property)\n            {\n                _property = property;\n                _treeView = new TableMultiColumnTreeView(property, this, ListGui)\n                {\n                    SelectionChangedCallback = SelectionChangedCallback,\n                };\n                _reloadRequired = true;\n            }\n\n            public override bool Update()\n            {\n                var dirty = base.Update();\n\n                dirty |= ReloadIfRequired();\n\n                if (dirty)\n                {\n                    _heightDirty = true;\n                    _treeView.multiColumnHeader.ResizeToFit();\n                }\n\n                return dirty;\n            }\n\n            public override float GetHeight(float width)\n            {\n                _treeView.Width = width;\n\n                if (_heightDirty)\n                {\n                    _heightDirty = false;\n                    _treeView.RefreshHeight();\n                }\n\n                var height = 0f;\n                height += ListGui.headerHeight;\n\n                if (_property.IsExpanded)\n                {\n                    height += _treeView.totalHeight;\n                    height += ListGui.footerHeight;\n                    height += FooterExtraSpace;\n                }\n\n                return height;\n            }\n\n            public override void OnGUI(Rect position)\n            {\n                var headerRect = new Rect(position)\n                {\n                    height = ListGui.headerHeight,\n                };\n                var elementsRect = new Rect(position)\n                {\n                    yMin = headerRect.yMax,\n                    height = _treeView.totalHeight + FooterExtraSpace,\n                };\n                var elementsContentRect = new Rect(elementsRect)\n                {\n                    xMin = elementsRect.xMin + 1,\n                    xMax = elementsRect.xMax - 1,\n                    yMax = elementsRect.yMax - FooterExtraSpace,\n                };\n                var footerRect = new Rect(position)\n                {\n                    yMin = elementsRect.yMax,\n                };\n\n                if (!_property.IsExpanded)\n                {\n                    ReorderableListProxy.DoListHeader(ListGui, headerRect);\n                    return;\n                }\n\n                if (Event.current.isMouse && Event.current.type == EventType.MouseDrag)\n                {\n                    _heightDirty = true;\n                    _treeView.multiColumnHeader.ResizeToFit();\n                }\n\n                if (Event.current.type == EventType.Repaint)\n                {\n                    ReorderableListProxy.defaultBehaviours.boxBackground.Draw(elementsRect,\n                        false, false, false, false);\n                }\n\n                ReorderableListProxy.DoListHeader(ListGui, headerRect);\n\n                EditorGUI.BeginChangeCheck();\n\n                _treeView.OnGUI(elementsContentRect);\n\n                if (EditorGUI.EndChangeCheck())\n                {\n                    _heightDirty = true;\n                    _property.PropertyTree.RequestRepaint();\n                }\n\n                ReorderableListProxy.defaultBehaviours.DrawFooter(footerRect, ListGui);\n            }\n\n            private bool ReloadIfRequired()\n            {\n                if (!_reloadRequired &&\n                    _property.IsExpanded == _isExpanded &&\n                    _property.ArrayElementProperties.Count == _arraySize)\n                {\n                    return false;\n                }\n\n                _reloadRequired = false;\n                _isExpanded = _property.IsExpanded;\n                _arraySize = _property.ArrayElementProperties.Count;\n\n                _treeView.Reload();\n\n                return true;\n            }\n\n            protected override TriElement CreateItemElement(TriProperty property)\n            {\n                return new TableRowElement(property);\n            }\n\n            private void SelectionChangedCallback(int index)\n            {\n                ListGui.index = index;\n            }\n        }\n\n        [Serializable]\n        private class TableMultiColumnTreeView : TreeView\n        {\n            private readonly TriProperty _property;\n            private readonly TriElement _cellElementContainer;\n            private readonly ReorderableList _listGui;\n            private readonly TableListPropertyOverrideContext _propertyOverrideContext;\n            private readonly bool _showAlternatingBackground;\n\n            private bool _wasRendered;\n\n            public Action<int> SelectionChangedCallback;\n\n            public TableMultiColumnTreeView(TriProperty property, TriElement container, ReorderableList listGui)\n                : base(new TreeViewState(), new TableColumnHeader())\n            {\n                property.TryGetAttribute(out ListDrawerSettingsAttribute listSettings);\n\n                _property = property;\n                _cellElementContainer = container;\n                _listGui = listGui;\n                _showAlternatingBackground = listSettings?.ShowAlternatingBackground ?? true;\n                _propertyOverrideContext = new TableListPropertyOverrideContext(property);\n\n                showAlternatingRowBackgrounds = true;\n                showBorder = false;\n                useScrollView = false;\n\n                multiColumnHeader.ResizeToFit();\n                multiColumnHeader.visibleColumnsChanged += header => header.ResizeToFit();\n            }\n\n            public float Width { get; set; }\n\n            public void RefreshHeight()\n            {\n                RefreshCustomRowHeights();\n            }\n\n            protected override void SelectionChanged(IList<int> selectedIds)\n            {\n                base.SelectionChanged(selectedIds);\n\n                if (SelectionChangedCallback != null && selectedIds.Count == 1)\n                {\n                    SelectionChangedCallback.Invoke(selectedIds[0]);\n                }\n            }\n\n            protected override TreeViewItem BuildRoot()\n            {\n                var root = new TreeViewItem(0, -1, string.Empty);\n                var columns = new List<MultiColumnHeaderState.Column>\n                {\n                    new MultiColumnHeaderState.Column\n                    {\n                        width = 16, autoResize = false, canSort = false, allowToggleVisibility = false,\n                    },\n                };\n\n                if (_property.IsExpanded)\n                {\n                    for (var index = 0; index < _property.ArrayElementProperties.Count; index++)\n                    {\n                        var rowChildProperty = _property.ArrayElementProperties[index];\n                        root.AddChild(new TableTreeItem(index, rowChildProperty));\n\n                        if (index == 0)\n                        {\n                            foreach (var kvp in ((TableRowElement) (_cellElementContainer.GetChild(0))).Elements)\n                            {\n                                columns.Add(new MultiColumnHeaderState.Column\n                                {\n                                    headerContent = kvp.Value,\n                                    headerTextAlignment = TextAlignment.Center,\n                                    autoResize = true,\n                                    canSort = false,\n                                });\n                            }\n                        }\n                    }\n                }\n\n                if (root.children == null)\n                {\n                    root.AddChild(new TableTreeEmptyItem());\n                }\n\n                if (multiColumnHeader.state == null ||\n                    multiColumnHeader.state.columns.Length == 1)\n                {\n                    multiColumnHeader.state = new MultiColumnHeaderState(columns.ToArray());\n                }\n\n                return root;\n            }\n\n            protected override float GetCustomRowHeight(int row, TreeViewItem item)\n            {\n                if (item is TableTreeEmptyItem)\n                {\n                    return EditorGUIUtility.singleLineHeight;\n                }\n\n                var height = 0f;\n                var rowElement = (TableRowElement) _cellElementContainer.GetChild(row);\n\n                foreach (var visibleColumnIndex in multiColumnHeader.state.visibleColumns)\n                {\n                    var cellWidth = _wasRendered\n                        ? multiColumnHeader.GetColumnRect(visibleColumnIndex).width\n                        : Width / Mathf.Max(1, multiColumnHeader.state.visibleColumns.Length);\n\n                    var cellHeight = visibleColumnIndex == 0\n                        ? EditorGUIUtility.singleLineHeight\n                        : rowElement.Elements[visibleColumnIndex - 1].Key.GetHeight(cellWidth);\n\n                    height = Math.Max(height, cellHeight);\n                }\n\n                return height + EditorGUIUtility.standardVerticalSpacing * 2;\n            }\n\n            protected override void RowGUI(RowGUIArgs args)\n            {\n                if (args.item is TableTreeEmptyItem)\n                {\n                    base.RowGUI(args);\n                    return;\n                }\n\n                if (_showAlternatingBackground && args.row % 2 != 0)\n                {\n                    EditorGUI.DrawRect(args.rowRect, new Color(0.1f, 0.1f, 0.1f, 0.15f));\n                }\n\n                var rowElement = (TableRowElement) _cellElementContainer.GetChild(args.row);\n\n                for (var i = 0; i < multiColumnHeader.state.visibleColumns.Length; i++)\n                {\n                    var visibleColumnIndex = multiColumnHeader.state.visibleColumns[i];\n                    var rowIndex = args.row;\n\n                    var cellRect = args.GetCellRect(i);\n                    cellRect.yMin += EditorGUIUtility.standardVerticalSpacing;\n\n                    if (visibleColumnIndex == 0)\n                    {\n                        ReorderableListProxy.defaultBehaviours.DrawElementDraggingHandle(cellRect, rowIndex,\n                            _listGui.index == rowIndex, _listGui.index == rowIndex, _listGui.draggable);\n                        continue;\n                    }\n\n                    var cellElement = rowElement.Elements[visibleColumnIndex - 1].Key;\n                    cellRect.height = cellElement.GetHeight(cellRect.width);\n\n                    using (TriGuiHelper.PushLabelWidth(EditorGUIUtility.labelWidth / rowElement.ChildrenCount))\n                    using (TriPropertyOverrideContext.BeginOverride(_propertyOverrideContext))\n                    {\n                        cellElement.OnGUI(cellRect);\n                    }\n                }\n\n                _wasRendered = true;\n            }\n        }\n\n        public class TableRowElement : TriPropertyCollectionBaseElement\n        {\n            public TableRowElement(TriProperty property)\n            {\n                DeclareGroups(property.ValueType);\n\n                Elements = new List<KeyValuePair<TriElement, GUIContent>>();\n\n                if (property.PropertyType == TriPropertyType.Generic)\n                {\n                    foreach (var childProperty in property.ChildrenProperties)\n                    {\n                        var oldChildrenCount = ChildrenCount;\n\n                        var props = new TriPropertyElement.Props\n                        {\n                            forceInline = true,\n                        };\n                        AddProperty(childProperty, props, out var group);\n\n                        if (oldChildrenCount != ChildrenCount)\n                        {\n                            var element = GetChild(ChildrenCount - 1);\n                            var headerContent = new GUIContent(group ?? childProperty.DisplayName);\n\n                            Elements.Add(new KeyValuePair<TriElement, GUIContent>(element, headerContent));\n                        }\n                    }\n                }\n                else\n                {\n                    var element = new TriPropertyElement(property, new TriPropertyElement.Props\n                    {\n                        forceInline = true,\n                    });\n                    var headerContent = new GUIContent(\"Element\");\n\n                    AddChild(element);\n                    Elements.Add(new KeyValuePair<TriElement, GUIContent>(element, headerContent));\n                }\n            }\n\n            public List<KeyValuePair<TriElement, GUIContent>> Elements { get; }\n        }\n\n        [Serializable]\n        private class TableColumnHeader : MultiColumnHeader\n        {\n            public TableColumnHeader() : base(null)\n            {\n                canSort = false;\n                height = DefaultGUI.minimumHeight;\n            }\n        }\n\n        [Serializable]\n        private class TableTreeEmptyItem : TreeViewItem\n        {\n            public TableTreeEmptyItem() : base(0, 0, \"Table is Empty\")\n            {\n            }\n        }\n\n        [Serializable]\n        private class TableTreeItem : TreeViewItem\n        {\n            public TableTreeItem(int id, TriProperty property) : base(id, 0)\n            {\n                Property = property;\n            }\n\n            public TriProperty Property { get; }\n        }\n\n        private class TableListPropertyOverrideContext : TriPropertyOverrideContext\n        {\n            private readonly TriProperty _grandParentProperty;\n            private readonly GUIContent _noneLabel = GUIContent.none;\n\n            public TableListPropertyOverrideContext(TriProperty grandParentProperty)\n            {\n                _grandParentProperty = grandParentProperty;\n            }\n\n            public override bool TryGetDisplayName(TriProperty property, out GUIContent displayName)\n            {\n                if (property.PropertyType == TriPropertyType.Primitive &&\n                    property.Parent?.Parent == _grandParentProperty &&\n                    !property.TryGetAttribute(out GroupAttribute _))\n                {\n                    displayName = _noneLabel;\n                    return true;\n                }\n\n                displayName = default;\n                return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/TableListDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 08ffdef4b26f43f5bb964ff72b883cdd\ntimeCreated: 1642780682"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/TitleDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Resolvers;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(TitleDrawer), TriDrawerOrder.Inspector)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class TitleDrawer : TriAttributeDrawer<TitleAttribute>\n    {\n        private const int SpaceBeforeTitle = 9;\n        private const int SpaceBeforeLine = 2;\n        private const int LineHeight = 2;\n        private const int SpaceBeforeContent = 3;\n\n        private ValueResolver<string> _titleResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            base.Initialize(propertyDefinition);\n\n            _titleResolver = ValueResolver.ResolveString(propertyDefinition, Attribute.Title);\n\n            if (_titleResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override float GetHeight(float width, TriProperty property, TriElement next)\n        {\n            var extraHeight = SpaceBeforeTitle +\n                              EditorGUIUtility.singleLineHeight +\n                              SpaceBeforeLine +\n                              LineHeight\n                              + SpaceBeforeContent;\n\n            return next.GetHeight(width) + extraHeight;\n        }\n\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            var titleRect = new Rect(position)\n            {\n                y = position.y + SpaceBeforeTitle,\n                height = EditorGUIUtility.singleLineHeight,\n            };\n\n            var lineRect = new Rect(position)\n            {\n                y = titleRect.yMax + SpaceBeforeLine,\n                height = LineHeight,\n            };\n\n            var contentRect = new Rect(position)\n            {\n                yMin = lineRect.yMax + SpaceBeforeContent,\n            };\n\n            var title = _titleResolver.GetValue(property, \"Error\");\n            GUI.Label(titleRect, title, EditorStyles.boldLabel);\n\n            if (Attribute.HorizontalLine)\n            {\n                EditorGUI.DrawRect(lineRect, Color.gray);\n            }\n\n            next.OnGUI(contentRect);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/TitleDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 2ad25a9f98e94ba1aafe184b7fed387d\ntimeCreated: 1638944499"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/UnitDrawer.cs",
    "content": "using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Drawers;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Utilities;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeDrawer(typeof(UnitDrawer), TriDrawerOrder.Decorator)]\n\nnamespace VirtueSky.Inspector.Drawers\n{\n    public class UnitDrawer : TriAttributeDrawer<UnitAttribute>\n    {\n        /// <summary>\n        /// Defines the padding to the right of the unit label towards the editable input field\n        /// </summary>\n        private const int PaddingRight = 5;\n\n        private ValueResolver<string> _unitResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            base.Initialize(propertyDefinition);\n\n            _unitResolver = ValueResolver.ResolveString(propertyDefinition, Attribute.unitToDisplay);\n\n            if (_unitResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override void OnGUI(Rect position, TriProperty property, TriElement next)\n        {\n            var unit = _unitResolver.GetValue(property, \"\");\n            var size = Styles.UnitStyle.CalcSize(TriGuiHelper.TempContent(unit));\n\n            var unitRect = new Rect(position.xMax - size.x - PaddingRight, position.y, size.x, position.height);\n\n            // Render the editable input field\n            next.OnGUI(position);\n\n            //Change color to grey\n            using (TriGuiHelper.PushColor(Color.grey))\n            {\n                // Render the unit as a suffix in the unitRect\n                EditorGUI.LabelField(unitRect, unit);\n            }\n        }\n\n        private static class Styles\n        {\n            public static readonly GUIStyle UnitStyle;\n\n            static Styles()\n            {\n                UnitStyle = new GUIStyle(EditorStyles.label);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers/UnitDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 409a22ba704c4806a28447600abae6d1\ntimeCreated: 1758476787"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Drawers.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 62b6b24478bb48c4acc0f072f2687607\ntimeCreated: 1639376870"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriBoxGroupDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.GroupDrawers;\n\n[assembly: RegisterTriGroupDrawer(typeof(TriBoxGroupDrawer))]\n\nnamespace VirtueSky.Inspector.GroupDrawers\n{\n    public class TriBoxGroupDrawer : TriGroupDrawer<DeclareBoxGroupAttribute>\n    {\n        public override TriPropertyCollectionBaseElement CreateElement(DeclareBoxGroupAttribute attribute)\n        {\n            return new TriBoxGroupElement(new TriBoxGroupElement.Props\n            {\n                title = attribute.Title,\n                titleMode = attribute.HideTitle\n                    ? TriBoxGroupElement.TitleMode.Hidden\n                    : TriBoxGroupElement.TitleMode.Normal,\n                hideIfChildrenInvisible = true,\n            });\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriBoxGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 735d0d9ee1cc4692ac11013b95983551\ntimeCreated: 1639417619"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriFoldoutGroupDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.GroupDrawers;\n\n[assembly: RegisterTriGroupDrawer(typeof(TriFoldoutGroupDrawer))]\n\nnamespace VirtueSky.Inspector.GroupDrawers\n{\n    public class TriFoldoutGroupDrawer : TriGroupDrawer<DeclareFoldoutGroupAttribute>\n    {\n        public override TriPropertyCollectionBaseElement CreateElement(DeclareFoldoutGroupAttribute attribute)\n        {\n            return new TriBoxGroupElement(new TriBoxGroupElement.Props\n            {\n                title = attribute.Title,\n                titleMode = TriBoxGroupElement.TitleMode.Foldout,\n                expandedByDefault = attribute.Expanded,\n                hideIfChildrenInvisible = true,\n            });\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriFoldoutGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ebf8a67d451c4932a7502f7f220cc938\ntimeCreated: 1668331607"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriHorizontalGroupDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.GroupDrawers;\nusing UnityEngine;\n\n[assembly: RegisterTriGroupDrawer(typeof(TriHorizontalGroupDrawer))]\n\nnamespace VirtueSky.Inspector.GroupDrawers\n{\n    public class TriHorizontalGroupDrawer : TriGroupDrawer<DeclareHorizontalGroupAttribute>\n    {\n        public override TriPropertyCollectionBaseElement CreateElement(DeclareHorizontalGroupAttribute attribute)\n        {\n            return new TriHorizontalGroupElement(attribute.Sizes);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriHorizontalGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 866eb8cc0f46446b8ceb1b2cb78b344c\ntimeCreated: 1640871674"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriTabGroupDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.GroupDrawers;\n\n[assembly: RegisterTriGroupDrawer(typeof(TriTabGroupDrawer))]\n\nnamespace VirtueSky.Inspector.GroupDrawers\n{\n    public class TriTabGroupDrawer : TriGroupDrawer<DeclareTabGroupAttribute>\n    {\n        public override TriPropertyCollectionBaseElement CreateElement(DeclareTabGroupAttribute attribute)\n        {\n            return new TriTabGroupElement();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriTabGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 2d4f714ffdae47c79edb698ab906daea\ntimeCreated: 1642758980"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriToggleGroupDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.GroupDrawers;\n\n[assembly: RegisterTriGroupDrawer(typeof(TriToggleGroupDrawer))]\n\nnamespace VirtueSky.Inspector.GroupDrawers\n{\n    public class TriToggleGroupDrawer : TriGroupDrawer<DeclareToggleGroupAttribute>\n    {\n        public override TriPropertyCollectionBaseElement CreateElement(DeclareToggleGroupAttribute attribute)\n        {\n            return new TriBoxGroupElement(new TriBoxGroupElement.Props\n            {\n                title = attribute.Title,\n                titleMode = TriBoxGroupElement.TitleMode.Toggle,\n                expandedByDefault = attribute.Collapsible,\n                hideIfChildrenInvisible = true,\n            });\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriToggleGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: cfcf76d363a541e39de3654d978a39ac\ntimeCreated: 1680888338"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriVerticalGroupDrawer.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Elements;\nusing VirtueSky.Inspector.GroupDrawers;\n\n[assembly: RegisterTriGroupDrawer(typeof(TriVerticalGroupDrawer))]\n\nnamespace VirtueSky.Inspector.GroupDrawers\n{\n    public class TriVerticalGroupDrawer : TriGroupDrawer<DeclareVerticalGroupAttribute>\n    {\n        public override TriPropertyCollectionBaseElement CreateElement(DeclareVerticalGroupAttribute attribute)\n        {\n            return new TriVerticalGroupElement();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers/TriVerticalGroupDrawer.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 20ea0129773b41ea8a2f43a18da811f4\ntimeCreated: 1643558679"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/GroupDrawers.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f1f781f159fb4215882cf59a6c4cbfa4\ntimeCreated: 1639417598"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/DisableIfProcessor.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Processors;\nusing VirtueSky.Inspector.Resolvers;\n\n[assembly: RegisterTriPropertyDisableProcessor(typeof(DisableIfProcessor))]\n\nnamespace VirtueSky.Inspector.Processors\n{\n    public class DisableIfProcessor : TriPropertyDisableProcessor<DisableIfAttribute>\n    {\n        private ValueResolver<object> _conditionResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            base.Initialize(propertyDefinition);\n\n            _conditionResolver = ValueResolver.Resolve<object>(propertyDefinition, Attribute.Condition);\n            if (_conditionResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public sealed override bool IsDisabled(TriProperty property)\n        {\n            var val = _conditionResolver.GetValue(property);\n            var equal = val?.Equals(Attribute.Value) ?? Attribute.Value == null;\n            return equal != Attribute.Inverse;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/DisableIfProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d369bf6c40b447ae95d39125ed769582\ntimeCreated: 1652289896"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/DisableInEditModeProcessor.cs",
    "content": "﻿using VirtueSky.Inspector.Processors;\nusing VirtueSky.Inspector;\nusing UnityEngine;\n\n[assembly: RegisterTriPropertyDisableProcessor(typeof(DisableInEditModeProcessor))]\n\nnamespace VirtueSky.Inspector.Processors\n{\n    public class DisableInEditModeProcessor : TriPropertyDisableProcessor<DisableInEditModeAttribute>\n    {\n        public override bool IsDisabled(TriProperty property)\n        {\n            return Application.isPlaying == Attribute.Inverse;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/DisableInEditModeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 25cd746f35a64f10805d0983690a10f1\ntimeCreated: 1642586603"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/DisableInPlayModeProcessor.cs",
    "content": "﻿using VirtueSky.Inspector.Processors;\nusing VirtueSky.Inspector;\nusing UnityEngine;\n\n[assembly: RegisterTriPropertyDisableProcessor(typeof(DisableInPlayModeProcessor))]\n\nnamespace VirtueSky.Inspector.Processors\n{\n    public class DisableInPlayModeProcessor : TriPropertyDisableProcessor<DisableInPlayModeAttribute>\n    {\n        public override bool IsDisabled(TriProperty property)\n        {\n            return Application.isPlaying != Attribute.Inverse;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/DisableInPlayModeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 397dcddedf9a4f91931e5bdc40c668aa\ntimeCreated: 1641385800"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/HIdeInEditModeProcessor.cs",
    "content": "﻿using VirtueSky.Inspector.Processors;\nusing VirtueSky.Inspector;\nusing UnityEngine;\n\n[assembly: RegisterTriPropertyHideProcessor(typeof(HideInEditModeProcessor))]\n\nnamespace VirtueSky.Inspector.Processors\n{\n    public class HideInEditModeProcessor : TriPropertyHideProcessor<HideInEditModeAttribute>\n    {\n        public override bool IsHidden(TriProperty property)\n        {\n            return Application.isPlaying == Attribute.Inverse;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/HIdeInEditModeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1d8995c5efd94e069afca842fc79aab6\ntimeCreated: 1642586621"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/HideIfProcessor.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Processors;\nusing VirtueSky.Inspector.Resolvers;\n\n[assembly: RegisterTriPropertyHideProcessor(typeof(HideIfProcessor))]\n\nnamespace VirtueSky.Inspector.Processors\n{\n    public class HideIfProcessor : TriPropertyHideProcessor<HideIfAttribute>\n    {\n        private ValueResolver<object> _conditionResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            base.Initialize(propertyDefinition);\n\n            _conditionResolver = ValueResolver.Resolve<object>(propertyDefinition, Attribute.Condition);\n\n            if (_conditionResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public sealed override bool IsHidden(TriProperty property)\n        {\n            var val = _conditionResolver.GetValue(property);\n            var equal = val?.Equals(Attribute.Value) ?? Attribute.Value == null;\n            return equal != Attribute.Inverse;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/HideIfProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 141d6b9341384ad58f40cd214c6be095\ntimeCreated: 1652289316"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/HideInPlayModeProcessor.cs",
    "content": "﻿using VirtueSky.Inspector.Processors;\nusing VirtueSky.Inspector;\nusing UnityEngine;\n\n[assembly: RegisterTriPropertyHideProcessor(typeof(HideInPlayModeProcessor))]\n\nnamespace VirtueSky.Inspector.Processors\n{\n    public class HideInPlayModeProcessor : TriPropertyHideProcessor<HideInPlayModeAttribute>\n    {\n        public override bool IsHidden(TriProperty property)\n        {\n            return Application.isPlaying != Attribute.Inverse;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors/HideInPlayModeProcessor.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 99642f3dada346b48762044cabacc69e\ntimeCreated: 1641384551"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Processors.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 3746e0c31b82450b804ea460d753f4fa\ntimeCreated: 1641384540"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/AssetsOnlyValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Validators;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeValidator(typeof(AssetsOnlyValidator))]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class AssetsOnlyValidator : TriAttributeValidator<AssetsOnlyAttribute>\n    {\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (!typeof(Object).IsAssignableFrom(propertyDefinition.FieldType))\n            {\n                return \"AssetsOnly attribute can be used only on Object fields\";\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            var obj = property.TryGetSerializedProperty(out var serializedProperty)\n                ? serializedProperty.objectReferenceValue\n                : (Object) property.Value;\n\n            if (obj == null || AssetDatabase.Contains(obj))\n            {\n                return TriValidationResult.Valid;\n            }\n\n            return TriValidationResult.Error($\"{obj} is not as asset.\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/AssetsOnlyValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 55b05031f9974136865973d335d322e0\ntimeCreated: 1654861744"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/DropdownValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Validators;\n\n[assembly: RegisterTriAttributeValidator(typeof(DropdownValidator<>), ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class DropdownValidator<T> : TriAttributeValidator<DropdownAttribute>\n    {\n        private DropdownValuesResolver<T> _valuesResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            _valuesResolver = DropdownValuesResolver<T>.Resolve(propertyDefinition, Attribute.Values);\n\n            if (_valuesResolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            foreach (var item in _valuesResolver.GetDropdownItems(property))\n            {\n                if (property.Comparer.Equals(item.Value, property.Value))\n                {\n                    return TriValidationResult.Valid;\n                }\n            }\n\n            var msg = $\"Dropdown value '{property.Value}' not valid\";\n\n            switch (Attribute.ValidationMessageType)\n            {\n                case TriMessageType.Info:\n                    return TriValidationResult.Info(msg);\n\n                case TriMessageType.Warning:\n                    return TriValidationResult.Warning(msg);\n\n                case TriMessageType.Error:\n                    return TriValidationResult.Error(msg);\n            }\n\n            return TriValidationResult.Valid;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/DropdownValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 22bd6d63410f4a7ba8564e185844ddbf\ntimeCreated: 1680714123"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/InfoBoxValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Validators;\n\n[assembly: RegisterTriAttributeValidator(typeof(InfoBoxValidator))]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class InfoBoxValidator : TriAttributeValidator<InfoBoxAttribute>\n    {\n        private ValueResolver<string> _resolver;\n        private ValueResolver<bool> _visibleIfResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            _resolver = ValueResolver.ResolveString(propertyDefinition, Attribute.Text);\n            _visibleIfResolver = Attribute.VisibleIf != null\n                ? ValueResolver.Resolve<bool>(propertyDefinition, Attribute.VisibleIf)\n                : null;\n\n            if (ValueResolver.TryGetErrorString(_resolver, _visibleIfResolver, out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            if (_visibleIfResolver != null && !_visibleIfResolver.GetValue(property))\n            {\n                return TriValidationResult.Valid;\n            }\n\n            var message = _resolver.GetValue(property, \"\");\n            return new TriValidationResult(false, message, Attribute.MessageType);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/InfoBoxValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d6a852249c1149edbbc1bd0e997726ad\ntimeCreated: 1652968861"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/MissingReferenceValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Validators;\nusing UnityEditor;\n\n[assembly: RegisterTriValueValidator(typeof(MissingReferenceValidator))]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class MissingReferenceValidator : TriValueValidator<UnityEngine.Object>\n    {\n        public override TriValidationResult Validate(TriValue<UnityEngine.Object> propertyValue)\n        {\n            if (propertyValue.Property.TryGetSerializedProperty(out var serializedProperty) &&\n                serializedProperty.propertyType == SerializedPropertyType.ObjectReference &&\n                serializedProperty.objectReferenceValue == null &&\n                serializedProperty.objectReferenceInstanceIDValue != 0)\n            {\n                return TriValidationResult.Warning($\"{GetName(propertyValue.Property)} is missing\");\n            }\n\n            return TriValidationResult.Valid;\n        }\n\n        private static string GetName(TriProperty property)\n        {\n            var name = property.DisplayName;\n            if (string.IsNullOrEmpty(name))\n            {\n                name = property.RawName;\n            }\n\n            return name;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/MissingReferenceValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e6349ecb04a34792bd193b53f6cc0ca3\ntimeCreated: 1642263604"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/RequiredValidator.cs",
    "content": "﻿using JetBrains.Annotations;\nusing VirtueSky.Inspector.Validators;\nusing VirtueSky.Inspector;\nusing VirtueSky.Inspector.Resolvers;\n\n[assembly: RegisterTriAttributeValidator(typeof(RequiredValidator), ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class RequiredValidator : TriAttributeValidator<RequiredAttribute>\n    {\n        [CanBeNull] private ActionResolver _fixActionResolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (Attribute.FixAction != null)\n            {\n                _fixActionResolver = ActionResolver.Resolve(propertyDefinition, Attribute.FixAction);\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            if (property.FieldType == typeof(string))\n            {\n                var isNull = string.IsNullOrEmpty((string) property.Value);\n                if (isNull)\n                {\n                    var message = Attribute.Message ?? $\"{GetName(property)} is required\";\n                    return MakeError(message, property);\n                }\n            }\n            else if (typeof(UnityEngine.Object).IsAssignableFrom(property.FieldType))\n            {\n                var isNull = null == (UnityEngine.Object) property.Value;\n                if (isNull)\n                {\n                    var message = Attribute.Message ?? $\"{GetName(property)} is required\";\n                    return MakeError(message, property);\n                }\n            }\n            else\n            {\n                return TriValidationResult.Error(\"RequiredAttribute only valid on Object and String\");\n            }\n\n            return TriValidationResult.Valid;\n        }\n\n        private TriValidationResult MakeError(string error, TriProperty property)\n        {\n            var result = TriValidationResult.Error(error);\n\n            if (_fixActionResolver != null)\n            {\n                result = AddFix(result, property);\n            }\n\n            return result;\n        }\n\n        private TriValidationResult AddFix(TriValidationResult result, TriProperty property)\n        {\n            return result.WithFix(() => _fixActionResolver?.InvokeForAllTargets(property), Attribute.FixActionName);\n        }\n\n        private static string GetName(TriProperty property)\n        {\n            var name = property.DisplayName;\n            if (string.IsNullOrEmpty(name))\n            {\n                name = property.RawName;\n            }\n\n            return name;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/RequiredValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 58b713b3023343c3b571cd1b3fa7fdab\ntimeCreated: 1642261781"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/SceneObjectsOnlyValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Validators;\nusing UnityEditor;\nusing UnityEngine;\n\n[assembly: RegisterTriAttributeValidator(typeof(SceneObjectsOnlyValidator))]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class SceneObjectsOnlyValidator : TriAttributeValidator<SceneObjectsOnlyAttribute>\n    {\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            if (!typeof(Object).IsAssignableFrom(propertyDefinition.FieldType))\n            {\n                return \"AssetsOnly attribute can be used only on Object fields\";\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            var obj = property.TryGetSerializedProperty(out var serializedProperty)\n                ? serializedProperty.objectReferenceValue\n                : (Object) property.Value;\n\n            if (obj == null || !AssetDatabase.Contains(obj))\n            {\n                return TriValidationResult.Valid;\n            }\n\n            return TriValidationResult.Error($\"{obj} cannot be an asset.\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/SceneObjectsOnlyValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 98948bb92a504f87abeda6e500dc22b2\ntimeCreated: 1657621306"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/SceneValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Validators;\nusing UnityEditor;\n\n[assembly: RegisterTriAttributeValidator(typeof(SceneValidator), ApplyOnArrayElement = true)]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class SceneValidator : TriAttributeValidator<SceneAttribute>\n    {\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            if (property.FieldType == typeof(string))\n            {\n                var value = (string) property.Value;\n\n                if (AssetDatabase.LoadAssetAtPath<SceneAsset>(value) == null)\n                {\n                    return TriValidationResult.Error($\"{value} not a valid scene\");\n                }\n\n                foreach (var scene in EditorBuildSettings.scenes)\n                {\n                    if (!property.Comparer.Equals(value, scene.path))\n                    {\n                        continue;\n                    }\n\n                    if (!scene.enabled)\n                    {\n                        return TriValidationResult.Error($\"{value} disabled in build settings\");\n                    }\n\n                    return TriValidationResult.Valid;\n                }\n\n                return TriValidationResult.Error($\"{value} not added to build settings\");\n            }\n\n            return TriValidationResult.Valid;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/SceneValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 568b3c97e76048dd8a005d101b86a8e4\ntimeCreated: 1657958255"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/TypeMismatchValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Validators;\nusing UnityEditor;\n\n[assembly: RegisterTriValueValidator(typeof(TypeMismatchValidator<>))]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class TypeMismatchValidator<T> : TriValueValidator<T>\n        where T : UnityEngine.Object\n    {\n        public override TriValidationResult Validate(TriValue<T> propertyValue)\n        {\n            if (propertyValue.Property.TryGetSerializedProperty(out var serializedProperty) &&\n                serializedProperty.propertyType == SerializedPropertyType.ObjectReference &&\n                serializedProperty.objectReferenceValue != null &&\n                (serializedProperty.objectReferenceValue is T) == false)\n            {\n                var displayName = propertyValue.Property.DisplayName;\n                var actual = serializedProperty.objectReferenceValue.GetType().Name;\n                var expected = propertyValue.Property.FieldType.Name;\n                var msg = $\"{displayName} does not match the type: actual = {actual}, expected = {expected}\";\n                return TriValidationResult.Warning(msg);\n            }\n\n            return TriValidationResult.Valid;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/TypeMismatchValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 510766d9f1764aae8c21d517ebb2c392\ntimeCreated: 1652079793"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/ValidateInputValidator.cs",
    "content": "﻿using VirtueSky.Inspector;\nusing VirtueSky.Inspector.Resolvers;\nusing VirtueSky.Inspector.Validators;\n\n[assembly: RegisterTriAttributeValidator(typeof(ValidateInputValidator))]\n\nnamespace VirtueSky.Inspector.Validators\n{\n    public class ValidateInputValidator : TriAttributeValidator<ValidateInputAttribute>\n    {\n        private ValueResolver<TriValidationResult> _resolver;\n\n        public override TriExtensionInitializationResult Initialize(TriPropertyDefinition propertyDefinition)\n        {\n            base.Initialize(propertyDefinition);\n\n            _resolver = ValueResolver.Resolve<TriValidationResult>(propertyDefinition, Attribute.Method);\n\n            if (_resolver.TryGetErrorString(out var error))\n            {\n                return error;\n            }\n\n            return TriExtensionInitializationResult.Ok;\n        }\n\n        public override TriValidationResult Validate(TriProperty property)\n        {\n            if (_resolver.TryGetErrorString(out var error))\n            {\n                return TriValidationResult.Error(error);\n            }\n\n            return _resolver.GetValue(property);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators/ValidateInputValidator.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ae1b5ddc1e804ada8a15b6f1501674e0\ntimeCreated: 1651936935"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/Validators.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e710031376614be5903f943dc4c4d07f\ntimeCreated: 1642261774"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/VirtueSky.Sunflower.Inspector.Editor.Extras.asmdef",
    "content": "{\n    \"name\": \"VirtueSky.Sunflower.Inspector.Editor.Extras\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"Unity.InternalAPIEditorBridge.013\",\n        \"VirtueSky.Sunflower.Inspector\",\n        \"VirtueSky.Sunflower.Inspector.Editor\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": true,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": false,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras/VirtueSky.Sunflower.Inspector.Editor.Extras.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 7be4600869ec09d4ca9a37d1dbfbf1a2\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor.Extras.meta",
    "content": "fileFormatVersion: 2\nguid: a7f4b4fc58f88d3459559029b269259e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 992bfd855a98c4f45b7f93c37256f4ce\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Buttons/ButtonAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ButtonAttribute : Attribute\n    {\n        public ButtonAttribute()\n        {\n        }\n\n        public ButtonAttribute(string name)\n        {\n            Name = name;\n        }\n\n        public ButtonAttribute(ButtonSizes buttonSize, string name = null)\n        {\n            ButtonSize = (int) buttonSize;\n            Name = name;\n        }\n\n        public string Name { get; set; }\n        public int ButtonSize { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Buttons/ButtonAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e51add3a0ba64dc0b53c1e249277055f\ntimeCreated: 1642526402"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Buttons/EnumToggleButtonsAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class EnumToggleButtonsAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Buttons/EnumToggleButtonsAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 59ef9c0c92d344d3936b2f13088dca00\ntimeCreated: 1653817332"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Buttons.meta",
    "content": "fileFormatVersion: 2\nguid: 51e387526ca64f26b6f86d3126c59ed2\ntimeCreated: 1758477512"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Collections/ListDrawerSettings.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ListDrawerSettingsAttribute : Attribute\n    {\n        public bool Draggable { get; set; } = true;\n        public bool HideAddButton { get; set; }\n        public bool HideRemoveButton { get; set; }\n        public bool AlwaysExpanded { get; set; }\n        public bool ShowElementLabels { get; set; }\n        public bool ShowDefaultBackground { get; set; } = true;\n        public bool ShowAlternatingBackground { get; set; } = true;\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Collections/ListDrawerSettings.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d58dcfa9a4df4af09d44c31a6f74ab26\ntimeCreated: 1642779136"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Collections/TableListAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class TableListAttribute : ListDrawerSettingsAttribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Collections/TableListAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 45cc7574c4ae44c8946865f3fa2e6ea9\ntimeCreated: 1642780172"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Collections.meta",
    "content": "fileFormatVersion: 2\nguid: bcdbf1404ef74ed8926926561deddca1\ntimeCreated: 1758477557"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableIfAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DisableIfAttribute : Attribute\n    {\n        public DisableIfAttribute(string condition) : this(condition, true)\n        {\n        }\n\n        public DisableIfAttribute(string condition, object value)\n        {\n            Condition = condition;\n            Value = value;\n        }\n\n        public string Condition { get; }\n        public object Value { get; }\n\n        public bool Inverse { get; protected set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableIfAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4ec1214049344873acae8035eb78b75f\ntimeCreated: 1652288568"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInEditModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DisableInEditModeAttribute : Attribute\n    {\n        public bool Inverse { get; protected set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInEditModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d54c241ae2494cb690bf538785a746e6\ntimeCreated: 1642586566"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInPlayModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DisableInPlayModeAttribute : Attribute\n    {\n        public bool Inverse { get; protected set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/DisableInPlayModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: fe853178832f4dde824c372a06a22ae0\ntimeCreated: 1641385956"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableIfAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class EnableIfAttribute : DisableIfAttribute\n    {\n        public EnableIfAttribute(string condition) : this(condition, true)\n        {\n        }\n\n        public EnableIfAttribute(string condition, object value) : base(condition, value)\n        {\n            Inverse = true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableIfAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 41fe52005b34402693769f8acc64b54a\ntimeCreated: 1652288564"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInEditModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class EnableInEditModeAttribute : DisableInEditModeAttribute\n    {\n        public EnableInEditModeAttribute()\n        {\n            Inverse = true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInEditModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: bd4e31bd9809431fb5f23d078c28f5ee\ntimeCreated: 1642586583"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInPlayModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class EnableInPlayModeAttribute : DisableInPlayModeAttribute\n    {\n        public EnableInPlayModeAttribute()\n        {\n            Inverse = true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/EnableInPlayModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 9dc8b9775fe6475f8d9df0fe00e15c25\ntimeCreated: 1641385940"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideIfAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class HideIfAttribute : Attribute\n    {\n        public HideIfAttribute(string condition) : this(condition, true)\n        {\n        }\n\n        public HideIfAttribute(string condition, object value)\n        {\n            Condition = condition;\n            Value = value;\n        }\n\n        public string Condition { get; }\n        public object Value { get; }\n\n        public bool Inverse { get; protected set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideIfAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 86a795a37ba54419bf857f6044fd6b3e\ntimeCreated: 1652288556"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInEditModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class HideInEditModeAttribute : Attribute\n    {\n        public bool Inverse { get; protected set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInEditModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e2cd1bf1d1734eb69b9d93d8c5641a64\ntimeCreated: 1642586553"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInPlayModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class HideInPlayModeAttribute : Attribute\n    {\n        public bool Inverse { get; protected set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/HideInPlayModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 6686c4df436342e8a75b5ace13a2c590\ntimeCreated: 1641385927"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowIfAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ShowIfAttribute : HideIfAttribute\n    {\n        public ShowIfAttribute(string condition) : this(condition, true)\n        {\n        }\n\n        public ShowIfAttribute(string condition, object value) : base(condition, value)\n        {\n            Inverse = true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowIfAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0ff7bd77f2bd4e06be3d07c0f80355d8\ntimeCreated: 1652288560"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInEditModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ShowInEditModeAttribute : HideInEditModeAttribute\n    {\n        public ShowInEditModeAttribute()\n        {\n            Inverse = true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInEditModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 21be4e082bd244a6bb7f856c10c7650d\ntimeCreated: 1642586541"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInPlayModeAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ShowInPlayModeAttribute : HideInPlayModeAttribute\n    {\n        public ShowInPlayModeAttribute()\n        {\n            Inverse = true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals/ShowInPlayModeAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1129642ac27240c8844f2865f1d38e92\ntimeCreated: 1641384123"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Conditionals.meta",
    "content": "fileFormatVersion: 2\nguid: bb5a4a51148241f5b791502bf03ca92b\ntimeCreated: 1758477617"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Debug/ShowDrawerChainAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ShowDrawerChainAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Debug/ShowDrawerChainAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a2856c1dc9ed40ffbe250bf652baf8bb\ntimeCreated: 1638949439"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Debug.meta",
    "content": "fileFormatVersion: 2\nguid: 1aff85796b5f4c6c9485ee91e9714037\ntimeCreated: 1758477790"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/DisplayAsStringAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DisplayAsStringAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/DisplayAsStringAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ebe54f4dd6f747df9d376712f4aa9c93\ntimeCreated: 1678604646"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/DropdownAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DropdownAttribute : Attribute\n    {\n        public string Values { get; }\n\n        public TriMessageType ValidationMessageType { get; set; } = TriMessageType.Error;\n\n        public DropdownAttribute(string values)\n        {\n            Values = values;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/DropdownAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 715d2fca9b1e4330be5d88eddbbdd801\ntimeCreated: 1656933469"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/InlineEditorAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property |\n                    AttributeTargets.Class | AttributeTargets.Struct)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class InlineEditorAttribute : Attribute\n    {\n        public InlineEditorModes Mode { get; set; } = InlineEditorModes.GUIOnly;\n\n        public float PreviewHeight { get; set; } = 50;\n\n        public InlineEditorAttribute()\n        {\n        }\n\n        public InlineEditorAttribute(InlineEditorModes mode)\n        {\n            Mode = mode;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/InlineEditorAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1d09104644014c71b3b0c3b472b743a5\ntimeCreated: 1641657539"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/PreviewMeshAttribute.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class PreviewMeshAttribute : Attribute\n    {\n        public int Height { get; set; } = 200;\n        public int Width { get; set; } = -1;\n        public bool UseFoldout { get; set; } = true;\n        public PreviewMeshRotationMethod RotationMethod { get; set; } = PreviewMeshRotationMethod.Clamped;\n\n        public PreviewMeshAttribute()\n        {\n        }\n\n        public PreviewMeshAttribute(int height)\n        {\n            Height = height;\n        }\n\n        public PreviewMeshAttribute(int height, int width)\n        {\n            Height = height;\n            Width = width;\n        }\n\n        public PreviewMeshAttribute(int height, int width, bool useFoldout)\n        {\n            Height = height;\n            Width = width;\n            UseFoldout = useFoldout;\n        }\n\n        public PreviewMeshAttribute(int height, int width, bool useFoldout, PreviewMeshRotationMethod rotationMethod)\n        {\n            Height = height;\n            Width = width;\n            UseFoldout = useFoldout;\n            RotationMethod = rotationMethod;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/PreviewMeshAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cb7fdcc457c940e591f0ce6683df69bd\ntimeCreated: 1758476479"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/SceneAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class SceneAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/SceneAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: aec7c3bafdd64bc9b74b132631a1bcab\ntimeCreated: 1657956550"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/UnitAttribute.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class UnitAttribute : Attribute\n    {\n        public string unitToDisplay;\n\n        #region Base Units\n\n        public const string Meter = \"m\";\n        public const string Centimeter = \"cm\";\n        public const string Millimeter = \"mm\";\n        public const string Kilogram = \"kg\";\n        public const string Second = \"s\";\n        public const string Ampere = \"A\";\n        public const string Kelvin = \"K\";\n        public const string Mole = \"mol\";\n        public const string Candela = \"cd\";\n\n        #endregion\n\n        #region Derived Units\n\n        public const string Radian = \"rad\";\n        public const string Degree = \"°\";\n        public const string Gram = \"g\";\n        public const string Liter = \"L\";\n        public const string Hertz = \"Hz\";\n        public const string Newton = \"N\";\n        public const string Pascal = \"Pa\";\n        public const string Joule = \"J\";\n        public const string Watt = \"W\";\n        public const string Coulomb = \"C\";\n        public const string Volt = \"V\";\n        public const string Ohm = \"Ω\";\n        public const string Farad = \"F\";\n        public const string Tesla = \"T\";\n        public const string Celsius = \"°C\";\n\n        #endregion\n\n        #region Common Combinations\n\n        public const string MeterPerSecond = \"m/s\";\n        public const string MeterPerSquareSecond = \"m/s²\";\n\n        #endregion\n\n        #region Extended Physics Units\n\n        public const string Lux = \"lx\";\n        public const string Weber = \"Wb\";\n        public const string Sievert = \"Sv\";\n        public const string Henry = \"H\";\n        public const string Siemens = \"S\";\n        public const string Becquerel = \"Bq\";\n        public const string Gray = \"Gy\";\n        public const string Katal = \"kat\";\n\n        #endregion\n\n        public UnitAttribute(string unit)\n        {\n            unitToDisplay = unit;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators/UnitAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a79b04c7b9824365a3638394d00f1c33\ntimeCreated: 1758476936"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Decorators.meta",
    "content": "fileFormatVersion: 2\nguid: 0ddbd443c77b4ac289262b901090da8c\ntimeCreated: 1758477832"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareBoxGroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DeclareBoxGroupAttribute : DeclareGroupBaseAttribute\n    {\n        public DeclareBoxGroupAttribute(string path) : base(path)\n        {\n            Title = path;\n        }\n\n        public string Title { get; set; }\n        public bool HideTitle { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareBoxGroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 3b8ef8105f574de2b66a434ad3318390\ntimeCreated: 1639417269"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareFoldoutGroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DeclareFoldoutGroupAttribute : DeclareGroupBaseAttribute\n    {\n        public DeclareFoldoutGroupAttribute(string path) : base(path)\n        {\n            Title = path;\n        }\n\n        public string Title { get; set; }\n        public bool Expanded { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareFoldoutGroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 3f930db0458a4705940c19a0df585478\ntimeCreated: 1668331532"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareGroupBaseAttribute.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Inspector\n{\n    public abstract class DeclareGroupBaseAttribute : Attribute\n    {\n        protected DeclareGroupBaseAttribute(string path)\n        {\n            Path = path ?? \"None\";\n        }\n\n        public string Path { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareGroupBaseAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 29196c90aab84065a58211f71c9e280e\ntimeCreated: 1639419849"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareHorizontalGroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DeclareHorizontalGroupAttribute : DeclareGroupBaseAttribute\n    {\n        public DeclareHorizontalGroupAttribute(string path) : base(path)\n        {\n        }\n\n        public float[] Sizes { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareHorizontalGroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 9b5d0fa1c34e46bbb34e0ceb78a1e999\ntimeCreated: 1640871509"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareTabGroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DeclareTabGroupAttribute : DeclareGroupBaseAttribute\n    {\n        public DeclareTabGroupAttribute(string path) : base(path)\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareTabGroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 951a8c6083fe40a69430e6f53d5ba7a0\ntimeCreated: 1642758819"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareToggleGroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DeclareToggleGroupAttribute : DeclareGroupBaseAttribute\n    {\n        public DeclareToggleGroupAttribute(string path) : base(path)\n        {\n            Title = path;\n        }\n        \n        public string Title { get; set; }\n        public bool Collapsible { get; set; } = true;\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareToggleGroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f93204143e294161afc85d1c6a3c6d16\ntimeCreated: 1680887538"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareVerticalGroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DeclareVerticalGroupAttribute : DeclareGroupBaseAttribute\n    {\n        public DeclareVerticalGroupAttribute(string path) : base(path)\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/DeclareVerticalGroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f62994cb4c86471aba39b9a0e79ae93a\ntimeCreated: 1643558654"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/GroupAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class GroupAttribute : Attribute\n    {\n        public GroupAttribute(string path)\n        {\n            Path = path;\n        }\n\n        public string Path { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/GroupAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 34f746736a9e4b8db6093924652cf405\ntimeCreated: 1639412551"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/GroupNextAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing JetBrains.Annotations;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class GroupNextAttribute : Attribute\n    {\n        public GroupNextAttribute(string path)\n        {\n            Path = path;\n        }\n\n        [CanBeNull] public string Path { get; }\n    }\n\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class UnGroupNextAttribute : GroupNextAttribute\n    {\n        public UnGroupNextAttribute() : base(null)\n        {\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/GroupNextAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: fb210ae77e66474e92cb101f18052072\ntimeCreated: 1660802441"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/TabAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class TabAttribute : Attribute\n    {\n        public TabAttribute(string tab)\n        {\n            TabName = tab;\n        }\n\n        public string TabName { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups/TabAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 19d2d001ee784250be738bb1a51a0fc6\ntimeCreated: 1642758885"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Groups.meta",
    "content": "fileFormatVersion: 2\nguid: 898e22a237174c6284ea59a0a68952ef\ntimeCreated: 1758477958"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/HideMonoScriptAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage((AttributeTargets.Class | AttributeTargets.Struct))]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class HideMonoScriptAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/HideMonoScriptAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 306721f92da846b5aac744073764a4e2\ntimeCreated: 1673714382"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/HideReferencePickerAttribute.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    public class HideReferencePickerAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/HideReferencePickerAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d8c607fff5fe44e29891720c2daf2d6e\ntimeCreated: 1659516082"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/OnValueChangedAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class OnValueChangedAttribute : Attribute\n    {\n        public OnValueChangedAttribute(string method)\n        {\n            Method = method;\n        }\n\n        public string Method { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/OnValueChangedAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ae1fa081898a4d13b8612da57bc9a349\ntimeCreated: 1652265504"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/PropertyOrderAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class PropertyOrderAttribute : Attribute\n    {\n        public int Order { get; }\n\n        public PropertyOrderAttribute(int order)\n        {\n            Order = order;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/PropertyOrderAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e6de09475a1c44b38ce070f556f5f44d\ntimeCreated: 1638941803"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/ReadOnlyAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property |\n                    AttributeTargets.Class | AttributeTargets.Struct)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ReadOnlyAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/ReadOnlyAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 07201e1119294874acfd8417ba34199e\ntimeCreated: 1638885262"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/ShowInInspector.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ShowInInspectorAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc/ShowInInspector.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4d9e5878061041bfa097dda3756bc478\ntimeCreated: 1639243448"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Misc.meta",
    "content": "fileFormatVersion: 2\nguid: 67a58ebdcdcd4daa970078ef3395d3d2\ntimeCreated: 1758478036"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithTriInspectorAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DrawWithTriInspectorAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithTriInspectorAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 33460afbb365415a9ff9d9379f0cec59\ntimeCreated: 1652773384"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithUnityAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class DrawWithUnityAttribute : Attribute\n    {\n        public bool WithUiToolkit { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Others/DrawWithUnityAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 72a4f37291e74452877df4701818e180\ntimeCreated: 1668181199"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Others.meta",
    "content": "fileFormatVersion: 2\nguid: 685ca44a3b25482c9429f9d1dad382ef\ntimeCreated: 1758478137"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/GUIColorAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method |\n                    AttributeTargets.Class | AttributeTargets.Struct)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class GUIColorAttribute : Attribute\n    {\n        public Color Color { get; }\n        public string GetColor { get; }\n        \n        public GUIColorAttribute(float r, float g, float b, float a = 1f)\n        {\n            Color = new Color(r, g, b, a);\n        }\n        \n        public GUIColorAttribute(byte r, byte g, byte b, byte a = byte.MaxValue)\n        {\n            Color = new Color32(r, g, b, a);\n        }\n        \n        public GUIColorAttribute(string value)\n        {\n            if (value.StartsWith(\"$\"))\n            {\n                GetColor = value;\n                \n                return;\n            }\n            \n            if (ColorUtility.TryParseHtmlString(value, out var color))\n            {\n            }\n            else if (ColorUtility.TryParseHtmlString($\"#{value}\", out color))\n            {\n            }\n            else\n            {\n                color = Color.white;\n            }\n            \n            Color = color;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/GUIColorAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e9a20bec5b2a495e9a4035e1585ebfda\ntimeCreated: 1638943497"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/HideLabelAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class HideLabelAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/HideLabelAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 16ab42968e5c4f86ab9a607cb983508f\ntimeCreated: 1638868812"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/IndentAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class IndentAttribute : Attribute\n    {\n        public int Indent { get; }\n\n        public IndentAttribute() : this(1)\n        {\n        }\n\n        public IndentAttribute(int indent)\n        {\n            Indent = indent;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/IndentAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0f021bed86024c529a5a265fea051a9f\ntimeCreated: 1638947073"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/InlinePropertyAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property |\n                    AttributeTargets.Class | AttributeTargets.Struct)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class InlinePropertyAttribute : Attribute\n    {\n        public float LabelWidth { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/InlinePropertyAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e788cb72a55a4a69a703dd857b408ace\ntimeCreated: 1638947526"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/LabelTextAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class LabelTextAttribute : Attribute\n    {\n        public string Text { get; }\n\n        public LabelTextAttribute(string text)\n        {\n            Text = text;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/LabelTextAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c7dff14e608f492abd5a4e4c26d4fb5a\ntimeCreated: 1638876608"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/LabelWidthAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class LabelWidthAttribute : Attribute\n    {\n        public float Width { get; }\n\n        public LabelWidthAttribute(float width)\n        {\n            Width = width;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/LabelWidthAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: cb503940335041fd804649c32f07ab14\ntimeCreated: 1638948051"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/PropertySpaceAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method |\n                    AttributeTargets.Class | AttributeTargets.Struct)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class PropertySpaceAttribute : Attribute\n    {\n        public float SpaceBefore { get; set; }\n        public float SpaceAfter { get; set; }\n\n        public PropertySpaceAttribute()\n        {\n            SpaceBefore = 7;\n        }\n\n        public PropertySpaceAttribute(float spaceBefore = 0, float spaceAfter = 0)\n        {\n            SpaceBefore = spaceBefore;\n            SpaceAfter = spaceAfter;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/PropertySpaceAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 27a1f5f498a04cc0b7ffedc2d2e6a8ff\ntimeCreated: 1638942425"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/PropertyTooltipAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class PropertyTooltipAttribute : Attribute\n    {\n        public string Tooltip { get; }\n\n        public PropertyTooltipAttribute(string tooltip)\n        {\n            Tooltip = tooltip;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/PropertyTooltipAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a8086d3692f24b48b221ddf74c77bad6\ntimeCreated: 1638948288"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/TitleAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class TitleAttribute : Attribute\n    {\n        public string Title { get; }\n        public bool HorizontalLine { get; set; } = true;\n\n        public TitleAttribute(string title)\n        {\n            Title = title;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling/TitleAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 03c62d6e9c5c4b55bd2bf199b9745d95\ntimeCreated: 1638944189"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Styling.meta",
    "content": "fileFormatVersion: 2\nguid: 53735b40cbf149989d574b93c54a2948\ntimeCreated: 1758478168"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/AssetsOnlyAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class AssetsOnlyAttribute : Attribute\n    {\n        \n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/AssetsOnlyAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0b922aaf25df46a99d356711f341dc06\ntimeCreated: 1654861722"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/InfoBoxAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class InfoBoxAttribute : Attribute\n    {\n        public string Text { get; }\n        public TriMessageType MessageType { get; }\n        public string VisibleIf { get; }\n\n        public InfoBoxAttribute(string text, TriMessageType messageType = TriMessageType.Info, string visibleIf = null)\n        {\n            Text = text;\n            MessageType = messageType;\n            VisibleIf = visibleIf;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/InfoBoxAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 573a31308ca14b5381aa18ffbff0afe2\ntimeCreated: 1652897457"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/RequiredAttribute.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))]\n    public class RequiredAttribute : Attribute\n    {\n        public string Message { get; set; }\n\n        public string FixAction { get; set; }\n        public string FixActionName { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/RequiredAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d886b45ac8b1474db5cdfd07c859e616\ntimeCreated: 1642261718"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/SceneObjectsOnlyAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage((AttributeTargets.Field | AttributeTargets.Property))]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class SceneObjectsOnlyAttribute : Attribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/SceneObjectsOnlyAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 908b02bc0b5d4cdd88e952625ce0cbc7\ntimeCreated: 1657621281"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/ValidateInputAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class ValidateInputAttribute : Attribute\n    {\n        public string Method { get; }\n\n        public ValidateInputAttribute(string method)\n        {\n            Method = method;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators/ValidateInputAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0bcc52b28f694396ab43601214283428\ntimeCreated: 1651936866"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes/Validators.meta",
    "content": "fileFormatVersion: 2\nguid: 69ba815e716e4d92b94c8767f8bea652\ntimeCreated: 1758478264"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/Attributes.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 2898ff4f810f468ab3ad610520d4305a\ntimeCreated: 1638868804"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/ButtonSizes.cs",
    "content": "namespace VirtueSky.Inspector\n{\n    public enum ButtonSizes\n    {\n        Small = 0,\n        Medium = 22,\n        Large = 32,\n        Gigantic = 62,\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/ButtonSizes.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: a7580fa208fd4eb695fa8b9f9ca0c4d7\ntimeCreated: 1654532890"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EditorIconAttribute.cs",
    "content": "using System;\nusing System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    /// <summary>\n    /// Specify a texture name from your assets which you want to be assigned as an icon to the MonoScript.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class EditorIconAttribute : System.Attribute\n    {\n        public string Name { get; set; }\n\n        public EditorIconAttribute(string name)\n        {\n            Name = name;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EditorIconAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e2c7ac1f4999450ebc100d2a8b066c9e\ntimeCreated: 1708661065"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/ExtendEnumAttribute.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    [System.AttributeUsage(System.AttributeTargets.Field)]\n    public class ExtendEnumAttribute : PropertyAttribute\n    {\n        public readonly bool display = true;\n\n        public ExtendEnumAttribute(bool displayValues = true)\n        {\n            display = displayValues;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/ExtendEnumAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3b2227ae43a24ea4ca175eea402c04fb\ntimeCreated: 1521158383\nlicenseType: Store\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/SearchableEnumAttribute.cs",
    "content": "﻿using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field)]\n    public class SearchableEnumAttribute : PropertyAttribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue/SearchableEnumAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 3e33b73dbc7248f8887394985c78c798\ntimeCreated: 1700212218"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/EnumAttribue.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f40063f75ee445bcbae79b16de53f59f\ntimeCreated: 1700212523"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HeaderLineAttribute.cs",
    "content": "﻿using System;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    /// <summary>\n    /// Display a header with an underline\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]\n    public class HeaderLineAttribute : PropertyAttribute\n    {\n        public readonly string text;\n        public readonly bool isToUpper;\n        public readonly CustomColor colorText;\n        public readonly CustomColor colorLine;\n\n        //Constructor\n        public HeaderLineAttribute(string text, bool isToUpper = true, CustomColor colorText = CustomColor.LightGray, CustomColor colorLine = CustomColor.LightGray)\n        {\n            this.text = text;\n            this.isToUpper = isToUpper;\n            this.colorText = colorText;\n            this.colorLine = colorLine;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HeaderLineAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: dbba5ee7a24c4dadbed10d545be73cd9\ntimeCreated: 1700193284"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HelpBoxAttribute.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace VirtueSky.Inspector\n{\n    using System;\n    using UnityEngine;\n#if UNITY_EDITOR\n    using UnityEditor;\n\n\n    [AttributeUsage(AttributeTargets.Field, Inherited = true)]\n    [Conditional(\"UNITY_EDITOR\")]\n    public class HelpBoxAttribute : PropertyAttribute\n    {\n        public readonly string text;\n\n        // MessageType exists in UnityEditor namespace and can throw an exception when used outside the editor.\n        // We spoof MessageType at the bottom of this script to ensure that errors are not thrown when\n        // MessageType is unavailable.\n        public readonly MessageType type;\n\n\n        /// <summary>\n        /// Adds a HelpBox to the Unity property inspector above this field.\n        /// </summary>\n        /// <param name=\"text\">The help text to be displayed in the HelpBox.</param>\n        /// <param name=\"type\">The icon to be displayed in the HelpBox.</param>\n        public HelpBoxAttribute(string text, MessageType type = MessageType.Info)\n        {\n            this.text = text;\n            this.type = type;\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HelpBoxAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f511b1121a674d0386cffc689e1ee676\ntimeCreated: 1700132002"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HighlightAttribute.cs",
    "content": "﻿using System;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field)]\n    public class HighlightAttribute : PropertyAttribute\n    {\n        public CustomColor highColor;\n        public readonly string validateField;\n        public readonly object comparationValue;\n        public readonly object[] comparationValueArray;\n\n        public HighlightAttribute(CustomColor highColor = CustomColor.Yellow, string validateField = null, object comparationValue = null)\n        {\n            this.highColor = highColor;\n            this.validateField = validateField;\n            this.comparationValue = comparationValue;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/HighlightAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bc1638a497c24280b2e3fee427ff69bb\ntimeCreated: 1700214606"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/LayerAttribute.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public class LayerAttribute : PropertyAttribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/LayerAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: de8b721c495f43fe94c9d80be3a8f520\ntimeCreated: 1700035240"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TagAttribute.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public class TagAttribute : PropertyAttribute\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TagAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9ad4f47dcc7a426ab9ffc3a190908974\ntimeCreated: 1700034888"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TitleColorAttribute.cs",
    "content": "﻿using UnityEngine;\nusing System;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    [AttributeUsage(AttributeTargets.Field, Inherited = true)]\n    public class TitleColorAttribute : PropertyAttribute\n    {\n        #region Constants\n\n        public const float DefaultLineHeight = 1f;\n        public const CustomColor DefaultLineColor = CustomColor.LightGray;\n        public const CustomColor DefaultTitleColor = CustomColor.Bright;\n\n        #endregion\n\n        #region Properties\n\n        public string Title { get; private set; }\n        public float LineHeight { get; private set; }\n        public CustomColor LineColor { get; private set; }\n        public CustomColor TitleColor { get; private set; }\n        public string LineColorString { get; private set; }\n        public string TitleColorString { get; private set; }\n        public float Spacing { get; private set; }\n        public bool AlignTitleLeft { get; private set; }\n\n        #endregion\n\n        public TitleColorAttribute(string title = \"\", CustomColor titleColor = DefaultTitleColor,\n            CustomColor lineColor = DefaultLineColor, float lineHeight = DefaultLineHeight, float spacing = 14f,\n            bool alignTitleLeft = false)\n        {\n            Title = title;\n            TitleColor = titleColor;\n            LineColor = lineColor;\n            TitleColorString = ColorUtility.ToHtmlStringRGB(TitleColor.ToColor());\n            LineColorString = ColorUtility.ToHtmlStringRGB(LineColor.ToColor());\n            LineHeight = Mathf.Max(1f, lineHeight);\n            Spacing = spacing;\n            AlignTitleLeft = alignTitleLeft;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute/TitleColorAttribute.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 334193c2b3e0480298df5e23f0b8a5ff\ntimeCreated: 1700209198"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/Attribute.meta",
    "content": "fileFormatVersion: 2\nguid: 4e036ca84be44ff7824644af888aeaab\ntimeCreated: 1700035173"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/GUIDAttribute.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Inspector\n{\n    public class GUIDAttribute : PropertyAttribute\n    {\n        public string prefix;\n\n        public GUIDAttribute()\n        {\n            this.prefix = string.Empty;\n        }\n\n        public GUIDAttribute(string prefix)\n        {\n            this.prefix = prefix;\n        }\n    }\n\n#if UNITY_EDITOR\n    [CustomPropertyDrawer(typeof(GUIDAttribute))]\n    public class GuidAttributeDrawer : PropertyDrawer\n    {\n        string Prefix => (attribute as GUIDAttribute).prefix;\n\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            EditorGUI.BeginProperty(position, label, property);\n            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);\n\n            if (string.IsNullOrEmpty(property.stringValue))\n            {\n                property.stringValue = Prefix + SimpleMath.NewGuid();\n            }\n\n            var w = position.width * 0.3f;\n\n            position.width = position.width * 0.7f;\n            GUI.enabled = false;\n            EditorGUI.PropertyField(position, property, GUIContent.none);\n            GUI.enabled = true;\n\n            position.position += new Vector2(position.width, 0);\n            position.width = w;\n            if (GUI.Button(position, new GUIContent(\"Change\")))\n            {\n                if (!property.serializedObject.isEditingMultipleObjects)\n                    property.stringValue = Prefix + SimpleMath.NewGuid();\n            }\n\n            property.serializedObject.ApplyModifiedProperties();\n\n            EditorGUI.EndProperty();\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/GUIDAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: af21dbdd68a58c54b9e7cac394dd19f2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/NamedIdAttribute.cs",
    "content": "﻿using System.Text;\nusing UnityEditor;\nusing UnityEngine;\n\n#if UNITY_EDITOR\nusing VirtueSky.UtilsEditor;\n#endif\n\n\nnamespace VirtueSky.Inspector\n{\n    public class NamedIdAttribute : PropertyAttribute\n    {\n        public NamedIdAttribute()\n        {\n        }\n    }\n\n#if UNITY_EDITOR\n\n    [CustomPropertyDrawer(typeof(NamedIdAttribute))]\n    public class NamedIdAttributeDrawer : PropertyDrawer\n    {\n        NamedIdAttribute TargetAttribute => attribute as NamedIdAttribute;\n\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            EditorGUI.BeginProperty(position, label, property);\n\n            Context(position, property);\n\n            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);\n\n            var id = property.stringValue;\n            if (string.IsNullOrEmpty(id))\n            {\n                id = ToSnakeCase(property.serializedObject.targetObject.name);\n                property.stringValue = id;\n                property.serializedObject.ApplyModifiedProperties();\n            }\n\n            using (new EditorGUIUtils.DisabledGUI(true))\n            {\n                EditorGUI.TextField(position, id);\n            }\n\n            EditorGUI.EndProperty();\n        }\n\n        void Context(Rect rect, SerializedProperty property)\n        {\n            var current = Event.current;\n\n            if (rect.Contains(current.mousePosition) && current.type == EventType.ContextClick)\n            {\n                var menu = new GenericMenu();\n\n                menu.AddItem(new GUIContent(\"Reset\"), false,\n                    () =>\n                    {\n                        property.stringValue = ToSnakeCase(property.serializedObject.targetObject.name);\n                        property.serializedObject.ApplyModifiedProperties();\n                    });\n                menu.ShowAsContext();\n\n                current.Use();\n            }\n        }\n\n        public static string ToSnakeCase(string text)\n        {\n            if (text.Length < 2)\n            {\n                return text;\n            }\n\n            var sb = new StringBuilder();\n            sb.Append(char.ToLowerInvariant(text[0]));\n            for (var i = 1; i < text.Length; ++i)\n            {\n                var c = text[i];\n                if (char.IsUpper(c))\n                {\n                    sb.Append('_');\n                    sb.Append(char.ToLowerInvariant(c));\n                }\n                else\n                {\n                    sb.Append(c);\n                }\n            }\n\n            return sb.ToString();\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute/NamedIdAttribute.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 14c317c6f93a4a74f8a96614615d0986\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/CustomizeAttribute.meta",
    "content": "fileFormatVersion: 2\nguid: bc2a42be533525d41a7caff1fe74a815\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/InlineEditorModes.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Inspector\n{\n    [Flags]\n    public enum InlineEditorModes\n    {\n        GUIOnly = 1 << 0,\n        Header = 1 << 1,\n        Preview = 1 << 2,\n\n        GUIAndPreview = GUIOnly | Preview,\n        GUIAndHeader = GUIOnly | Header,\n        FullEditor = GUIOnly | Header | Preview,\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/InlineEditorModes.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f798a09b97da4ed09b5b962c0dbdba0e\ntimeCreated: 1712392526"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/PreviewMeshRotationMethod.cs",
    "content": "namespace VirtueSky.Inspector\n{\n    public enum PreviewMeshRotationMethod\n    {\n        Clamped,\n        Freeform,\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/PreviewMeshRotationMethod.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5088e59411a34e64b677765b78b045e6\ntimeCreated: 1758476637"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/TriDropdownList.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VirtueSky.Inspector\n{\n    public class TriDropdownList<T> : List<TriDropdownItem<T>>\n    {\n        public void Add(string text, T value)\n        {\n            Add(new TriDropdownItem<T> {Text = text, Value = value,});\n        }\n    }\n\n    public interface ITriDropdownItem\n    {\n        string Text { get; }\n        object Value { get; }\n    }\n\n    public struct TriDropdownItem : ITriDropdownItem\n    {\n        public string Text { get; set; }\n        public object Value { get; set; }\n    }\n\n    public struct TriDropdownItem<T> : ITriDropdownItem\n    {\n        public string Text;\n        public T Value;\n\n        string ITriDropdownItem.Text => Text;\n        object ITriDropdownItem.Value => Value;\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/TriDropdownList.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: bdeda5f861ce4f359c0a25554ffe70bf\ntimeCreated: 1656937692"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/TriValidationResult.cs",
    "content": "﻿using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Inspector\n{\n    public readonly struct TriValidationResult\n    {\n        public static TriValidationResult Valid => new TriValidationResult(true, null, TriMessageType.None);\n\n        public TriValidationResult(bool valid, string message, TriMessageType messageType,\n            Action fixAction = null, GUIContent fixActionContent = null)\n        {\n            IsValid = valid;\n            Message = message;\n            MessageType = messageType;\n            FixAction = fixAction;\n            FixActionContent = fixActionContent;\n        }\n\n        public bool IsValid { get; }\n        public string Message { get; }\n        public TriMessageType MessageType { get; }\n        public Action FixAction { get; }\n        public GUIContent FixActionContent { get; }\n\n        public TriValidationResult WithFix(Action action, string name = null)\n        {\n            return new TriValidationResult(IsValid, Message, MessageType, action, new GUIContent(name ?? \"Fix\"));\n        }\n\n        public static TriValidationResult Info(string error)\n        {\n            return new TriValidationResult(false, error, TriMessageType.Info);\n        }\n\n        public static TriValidationResult Error(string error)\n        {\n            return new TriValidationResult(false, error, TriMessageType.Error);\n        }\n\n        public static TriValidationResult Warning(string error)\n        {\n            return new TriValidationResult(false, error, TriMessageType.Warning);\n        }\n    }\n\n    public enum TriMessageType\n    {\n        None,\n        Info,\n        Warning,\n        Error,\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/TriValidationResult.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 428f8881a0d34edf8148591af6f9a0e7\ntimeCreated: 1642525992"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/VirtueSky.Sunflower.Inspector.asmdef",
    "content": "{\n    \"name\": \"VirtueSky.Sunflower.Inspector\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": true,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Inspector/Runtime/VirtueSky.Sunflower.Inspector.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 324caed91501a9c47a04ebfd87b68794\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 2e0eb7988fa380c4c90c94d3ba0a282f\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AdvancedDropdownProxy.cs",
    "content": "﻿using UnityEditor.IMGUI.Controls;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public class AdvancedDropdownProxy\n    {\n        public static void SetShowHeader(AdvancedDropdown dropdown, bool showHeader)\n        {\n            dropdown.m_WindowInstance.showHeader = showHeader;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AdvancedDropdownProxy.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: fbe08837c89a44e29ea221ffeadb811d\ntimeCreated: 1652084409"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AssemblyInfo.cs",
    "content": "﻿using System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"TriInspector.Editor\")]\n[assembly: InternalsVisibleTo(\"TriInspector.Editor.Extras\")]"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/AssemblyInfo.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: ceaac34ef4d54edea2f5bd49bc1145a5\ntimeCreated: 1652008241"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorGUIUtilityProxy.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public static class EditorGUIUtilityProxy\n    {\n        public static Texture2D GetHelpIcon(MessageType type)\n        {\n            return EditorGUIUtility.GetHelpIcon(type);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorGUIUtilityProxy.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0c34c0be768944a3ad89255c85434802\ntimeCreated: 1641381655"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorProxy.cs",
    "content": "﻿using UnityEditor;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public static class EditorProxy\n    {\n        public static void DoDrawDefaultInspector(SerializedObject obj)\n        {\n            Editor.DoDrawDefaultInspector(obj);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/EditorProxy.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 993f9dfd66614ba68fcf95c0e7e098e3\ntimeCreated: 1683783433"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public static class GUIClipProxy\n    {\n        private static Func<Vector2, Vector2> _guiClipUnClipVector2;\n        private static Func<Rect, Rect> _guiClipUnClipToWindowRect;\n        private static Func<Rect> _guiClipVisibleRect;\n\n        [InitializeOnLoadMethod]\n        private static void Setup()\n        {\n            var imGuiModuleAssembly = typeof(GUI).Assembly;\n            var guiClipType = imGuiModuleAssembly.GetType(\"UnityEngine.GUIClip\", throwOnError: true);\n\n            _guiClipUnClipVector2 = (Func<Vector2, Vector2>) Delegate.CreateDelegate(typeof(Func<Vector2, Vector2>),\n                guiClipType.GetMethod(\"Unclip\", new[] {typeof(Vector2)}));\n\n            _guiClipUnClipToWindowRect = (Func<Rect, Rect>) Delegate.CreateDelegate(typeof(Func<Rect, Rect>),\n                guiClipType.GetMethod(\"UnclipToWindow\", new[] {typeof(Rect)}));\n\n            _guiClipVisibleRect = (Func<Rect>) Delegate.CreateDelegate(typeof(Func<Rect>),\n                guiClipType.GetProperty(\"visibleRect\", BindingFlags.Static | BindingFlags.NonPublic).GetMethod);\n        }\n\n        public static Rect VisibleRect => _guiClipVisibleRect.Invoke();\n\n        public static Vector2 UnClip(Vector2 pos)\n        {\n            return _guiClipUnClipVector2.Invoke(pos);\n        }\n\n        public static Rect UnClipToWindow(Rect rect)\n        {\n            return _guiClipUnClipToWindowRect.Invoke(rect);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/GUIClipProxy.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e573403f6f844648ab1dc4013c8c4856\ntimeCreated: 1690734495"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/InternalEditorUtilityProxy.cs",
    "content": "﻿using UnityEditorInternal;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public static class InternalEditorUtilityProxy\n    {\n        public static bool GetIsInspectorExpanded(UnityEngine.Object obj)\n        {\n            return InternalEditorUtility.GetIsInspectorExpanded(obj);\n        }\n\n        public static void SetIsInspectorExpanded(UnityEngine.Object obj, bool isExpanded)\n        {\n            InternalEditorUtility.SetIsInspectorExpanded(obj, isExpanded);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/InternalEditorUtilityProxy.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c25961327a574e9399f5ebc2d9a929ea\ntimeCreated: 1642757678"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ReorderableListProxy.cs",
    "content": "using System;\nusing System.Reflection;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public static class ReorderableListProxy\n    {\n#if !UNITY_2021_3_OR_NEWER\n        private static readonly MethodInfo ClearCacheMethod;\n#endif\n\n        private static ReorderableList.Defaults _defaultBehaviours;\n\n        // ReSharper disable once InconsistentNaming\n        public static ReorderableList.Defaults defaultBehaviours\n        {\n            get\n            {\n                if (_defaultBehaviours == null)\n                {\n                    _defaultBehaviours = new ReorderableList.Defaults();\n                }\n\n                return _defaultBehaviours;\n            }\n        }\n\n        static ReorderableListProxy()\n        {\n#if !UNITY_2021_3_OR_NEWER\n            const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;\n            ClearCacheMethod = typeof(ReorderableList).GetMethod(\"InvalidateCacheRecursive\", flags) ??\n                               typeof(ReorderableList).GetMethod(\"ClearCacheRecursive\", flags);\n#endif\n        }\n\n        public static void DoListHeader(ReorderableList list, Rect headerRect)\n        {\n            if (list.showDefaultBackground && Event.current.type == EventType.Repaint)\n            {\n                defaultBehaviours.DrawHeaderBackground(headerRect);\n            }\n\n            headerRect.xMin += 6f;\n            headerRect.xMax -= 6f;\n            headerRect.height -= 2f;\n            headerRect.y += 1;\n\n            list.drawHeaderCallback?.Invoke(headerRect);\n        }\n\n        public static void ClearCacheRecursive(ReorderableList list)\n        {\n#if UNITY_2021_3_OR_NEWER\n            list.InvalidateCacheRecursive();\n#else\n            ClearCacheMethod?.Invoke(list, Array.Empty<object>());\n#endif\n        }\n\n        public static void DoAddButton(ReorderableList list, Object value)\n        {\n#if UNITY_2020_2_OR_NEWER\n            defaultBehaviours.DoAddButton(list, value);\n#else\n            defaultBehaviours.DoAddButton(list);\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ReorderableListProxy.cs.meta",
    "content": "fileFormatVersion: 2\nguid: acf8923868a81dd41825ea3ce86c0455\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs",
    "content": "﻿using UnityEditor;\nusing UnityEngine;\nusing UnityEngine.UIElements;\n\nnamespace VirtueSky.InspectorUnityInternalBridge\n{\n    public static class ScriptAttributeUtilityProxy\n    {\n        public static PropertyHandlerProxy GetHandler(SerializedProperty property)\n        {\n            var handler = ScriptAttributeUtility.GetHandler(property);\n            return new PropertyHandlerProxy(handler);\n        }\n    }\n\n    public readonly struct PropertyHandlerProxy\n    {\n        private readonly PropertyHandler _handler;\n\n        internal PropertyHandlerProxy(PropertyHandler handler)\n        {\n            _handler = handler;\n        }\n\n        // ReSharper disable once InconsistentNaming\n        public bool hasPropertyDrawer => _handler.hasPropertyDrawer;\n\n        public void SetPreferredLabel(string label)\n        {\n#if UNITY_2022_2_OR_NEWER\n            if (_handler.propertyDrawer != null)\n            {\n                _handler.propertyDrawer.m_PreferredLabel = label;\n            }\n#endif\n        }\n\n        public VisualElement CreatePropertyGUI(SerializedProperty property)\n        {\n            return _handler.propertyDrawer?.CreatePropertyGUI(property);\n        }\n\n        public float GetHeight(SerializedProperty property, GUIContent label, bool includeChildren)\n        {\n            return _handler.GetHeight(property, label, includeChildren);\n        }\n\n        public bool OnGUI(Rect position, SerializedProperty property, GUIContent label, bool includeChildren)\n        {\n            return _handler.OnGUI(position, property, label, includeChildren);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/ScriptAttributeUtilityProxy.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 9d3310787ea648a18e32a0da39a292c2\ntimeCreated: 1638773139"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/Unity.InternalAPIEditorBridge.013.asmdef",
    "content": "{\n    \"name\": \"Unity.InternalAPIEditorBridge.013\",\n    \"rootNamespace\": \"\",\n    \"references\": [],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012/Unity.InternalAPIEditorBridge.013.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 710c5eba4cfb6804d9772afbcd0a22eb\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Unity.InternalAPIEditorBridge.012.meta",
    "content": "fileFormatVersion: 2\nguid: 17812d8658d186345af6f2e6bbc1c31b\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector/Version.txt",
    "content": "Tri-Inspector: v1.15.1"
  },
  {
    "path": "VirtueSky/Inspector/Version.txt.meta",
    "content": "fileFormatVersion: 2\nguid: e662fde09058f4642a2a955bc82ab382\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Inspector.meta",
    "content": "fileFormatVersion: 2\nguid: 1e11cadef476da9428eeb37c6e6a03c7\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/LevelEditor/LevelEditor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEditor.SceneManagement;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.LevelEditor\n{\n    public class LevelEditor : EditorWindow\n    {\n        // private class PickObject\n        // {\n        //     public string group;\n        //     public GameObject pickedObject;\n        // }\n\n//         #region preview generator\n//\n//         private static PreviewGenerator previewGenerator;\n//\n//         private static PreviewGenerator PreviewGenerator\n//         {\n//             get\n//             {\n//                 var generator = previewGenerator;\n//                 if (generator != null) return generator;\n//\n//                 return previewGenerator = new PreviewGenerator\n//                 {\n//                     width = 512, height = 512, transparentBackground = true,\n//                     sizingType = PreviewGenerator.ImageSizeType.Fit\n//                 };\n//             }\n//         }\n//\n//         private static Dictionary<GameObject, Texture2D> previewDict;\n//\n//         public static void ClearPreviews()\n//         {\n//             if (previewDict != null)\n//             {\n//                 foreach (var kvp in previewDict.ToList())\n//                 {\n//                     previewDict[kvp.Key] = null;\n//                 }\n//\n//                 previewDict.Clear();\n//             }\n//         }\n//\n//         public static void ClearPreview(GameObject go)\n//         {\n//             if (previewDict?.TryGetValue(go, out var tex) ?? false)\n//             {\n//                 UnityEngine.Object.DestroyImmediate(tex);\n//                 previewDict.Remove(go);\n//             }\n//         }\n//\n//         public static Texture2D GetPreview(GameObject go, bool canCreate = true)\n//         {\n//             if (!go) return null;\n//             previewDict ??= new Dictionary<GameObject, Texture2D>();\n//             previewDict.TryGetValue(go, out var tex);\n//             if (!canCreate) return tex != null ? tex : default;\n//\n//             if (tex) return tex;\n//             tex = PreviewGenerator.CreatePreview(go.gameObject);\n//             previewDict[go] = tex;\n//\n//             return tex;\n//         }\n//\n//         #endregion\n//\n//\n//         private readonly string[] _optionsSpawn = { \"Default\", \"Index\", \"Custom\" };\n//         private readonly string[] _optionsMode = { \"Renderer\", \"Ignore\" };\n//\n//         private Vector2 _pickObjectScrollPosition;\n//         private Vector2 _whiteScrollPosition;\n//         private Vector2 _blackScrollPosition;\n//         private PickObject _currentPickObject;\n//         private List<PickObject> _pickObjects;\n//         private SerializedObject _pathFolderSerializedObject;\n//         private SerializedProperty _pathFolderProperty;\n//         private int _selectedSpawn;\n//         private int _selectedMode;\n//         private GameObject _rootSpawn;\n//         private int _rootIndexSpawn;\n//         private GameObject _previewPickupObject;\n//         private UnityEngine.Object _previousObjectInpectorPreview;\n//         private UnityEditor.Editor _editorInpsectorPreview;\n//\n//         private static Vector2 EventMousePoint\n//         {\n//             get\n//             {\n//                 var position = Event.current.mousePosition;\n//                 position.y = Screen.height - position.y - 60f;\n//                 return position;\n//             }\n//         }\n//\n//         private List<PickObject> PickObjects => _pickObjects ??= new List<PickObject>();\n//\n//\n//         private void OnEnable()\n//         {\n//             RefreshPickObject();\n//             SceneView.duringSceneGui += OnSceneGUI;\n//         }\n//\n//         private void OnDisable()\n//         {\n//             SceneView.duringSceneGui -= OnSceneGUI;\n//         }\n//\n//\n//         private void OnProjectChange()\n//         {\n//             TryClose();\n//         }\n//\n//         private void OnHierarchyChange()\n//         {\n//             TryClose();\n//         }\n//\n//         private bool TryClose()\n//         {\n//             return false;\n//         }\n//\n//         // ReSharper disable once UnusedMember.Local\n//         private void RefreshAll()\n//         {\n//             LevelEditor.ClearPreviews();\n//             RefreshPickObject();\n//             ClearEditor();\n//         }\n//\n//         /// <summary>\n//         /// display picked object in editor\n//         /// </summary>\n//         private void RefreshPickObject()\n//         {\n//             _pickObjects = new List<PickObject>();\n//             var blacklistAssets = new List<GameObject>();\n//             var whitelistAssets = new List<GameObject>();\n//             if (!LevelSystemEditorSetting.Instance.blacklistPaths.IsNullOrEmpty())\n//             {\n//                 blacklistAssets = AssetDatabase.FindAssets(\"t:GameObject\",\n//                         LevelSystemEditorSetting.Instance.blacklistPaths.ToArray())\n//                     .Select(AssetDatabase.GUIDToAssetPath)\n//                     .Select(AssetDatabase.LoadAssetAtPath<GameObject>)\n//                     .ToList();\n//\n//                 foreach (string blacklistPath in LevelSystemEditorSetting.Instance.blacklistPaths)\n//                 {\n//                     if (File.Exists(blacklistPath))\n//                         blacklistAssets.Add(\n//                             AssetDatabase.LoadAssetAtPath<GameObject>(blacklistPath));\n//                 }\n//             }\n//\n//             if (!LevelSystemEditorSetting.Instance.whitelistPaths.IsNullOrEmpty())\n//             {\n//                 whitelistAssets = AssetDatabase.FindAssets(\"t:GameObject\",\n//                         LevelSystemEditorSetting.Instance.whitelistPaths.ToArray())\n//                     .Select(AssetDatabase.GUIDToAssetPath)\n//                     .Select(AssetDatabase.LoadAssetAtPath<GameObject>)\n//                     .ToList();\n//\n//                 foreach (string whitelistPath in LevelSystemEditorSetting.Instance.whitelistPaths)\n//                 {\n//                     if (File.Exists(whitelistPath))\n//                         whitelistAssets.Add(\n//                             AssetDatabase.LoadAssetAtPath<GameObject>(whitelistPath));\n//                 }\n//             }\n//\n//             var resultAssets = whitelistAssets.Where(_ => !blacklistAssets.Contains(_));\n//             foreach (var o in resultAssets)\n//             {\n//                 string group = Path.GetDirectoryName(AssetDatabase.GetAssetPath(o))\n//                     ?.Replace('\\\\', '/').Split('/').Last();\n//                 var po = new PickObject { pickedObject = o.gameObject, group = group };\n//                 _pickObjects.Add(po);\n//             }\n//         }\n//\n//         private bool CheckEscape()\n//         {\n//             if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)\n//             {\n//                 _currentPickObject = null;\n//                 Repaint();\n//                 SceneView.RepaintAll();\n//                 return true;\n//             }\n//\n//             return false;\n//         }\n//\n//         private void OnGUI()\n//         {\n//             EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height),\n//                 GameDataEditor.ColorBackgroundRectWindowSunflower.ToColor());\n//             GUI.contentColor = GameDataEditor.ColorTextContentWindowSunflower.ToColor();\n//             GUI.backgroundColor = GameDataEditor.ColorContentWindowSunflower.ToColor();\n//             GUILayout.Space(8);\n//             if (TryClose()) return;\n//             if (CheckEscape()) return;\n//             SceneView.RepaintAll();\n//             InternalDrawDropArea();\n//             GUILayout.Space(4);\n//             InternalDrawSetting();\n//             GUILayout.Space(4);\n//             InternalDrawPickupArea();\n//         }\n//\n//         private void InternalDrawDropArea()\n//         {\n//             Uniform.DrawGroupFoldout(\"level_editor_drop_area\", \"Drop Area\", DrawDropArea, false);\n//\n//             void DrawDropArea()\n//             {\n//                 GUILayout.Space(2);\n//                 float width = 0;\n//                 var @event = Event.current;\n//\n//                 #region horizontal\n//\n//                 EditorGUILayout.BeginHorizontal();\n//                 var whiteArea = GUILayoutUtility.GetRect(0.0f, 50f, GUILayout.ExpandWidth(true));\n//                 var blackArea = GUILayoutUtility.GetRect(0.0f, 50f, GUILayout.ExpandWidth(true));\n//                 // ReSharper disable once CompareOfFloatsByEqualityOperator\n//                 if (whiteArea.width == 1f) width = position.width / 2;\n//                 else width = whiteArea.width;\n//                 GUI.backgroundColor = new Color(0f, 0.83f, 1f);\n//                 GUI.Box(whiteArea, \"[WHITE LIST]\",\n//                     new GUIStyle(EditorStyles.helpBox)\n//                         { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic });\n//                 GUI.backgroundColor = Color.white;\n//                 GUI.backgroundColor = new Color(1f, 0.13f, 0f);\n//                 GUI.Box(blackArea, \"[BLACK LIST]\",\n//                     new GUIStyle(EditorStyles.helpBox)\n//                         { alignment = TextAnchor.MiddleCenter, fontStyle = FontStyle.Italic });\n//                 GUI.backgroundColor = Color.white;\n//                 switch (@event.type)\n//                 {\n//                     case EventType.DragUpdated:\n//                     case EventType.DragPerform:\n//                         if (whiteArea.Contains(@event.mousePosition))\n//                         {\n//                             DragAndDrop.visualMode = DragAndDropVisualMode.Copy;\n//                             if (@event.type == EventType.DragPerform)\n//                             {\n//                                 DragAndDrop.AcceptDrag();\n//                                 foreach (string path in DragAndDrop.paths)\n//                                 {\n//                                     if (File.Exists(path))\n//                                     {\n//                                         var r = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(\n//                                             path);\n//                                         if (r.GetType() != typeof(GameObject)) continue;\n//                                     }\n//\n//                                     ValidateWhitelist(path,\n//                                         ref LevelSystemEditorSetting.Instance.blacklistPaths);\n//                                     AddToWhitelist(path);\n//                                 }\n//\n//                                 ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance\n//                                     .whitelistPaths);\n//                                 RefreshAll();\n//                             }\n//                         }\n//                         else if (blackArea.Contains(@event.mousePosition))\n//                         {\n//                             DragAndDrop.visualMode = DragAndDropVisualMode.Copy;\n//                             if (@event.type == EventType.DragPerform)\n//                             {\n//                                 DragAndDrop.AcceptDrag();\n//                                 foreach (string path in DragAndDrop.paths)\n//                                 {\n//                                     if (File.Exists(path))\n//                                     {\n//                                         var r = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(\n//                                             path);\n//                                         if (r.GetType() != typeof(GameObject)) continue;\n//                                     }\n//\n//                                     ValidateBlacklist(path,\n//                                         ref LevelSystemEditorSetting.Instance.whitelistPaths);\n//                                     AddToBlacklist(path);\n//                                 }\n//\n//                                 ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance\n//                                     .blacklistPaths);\n//                                 RefreshAll();\n//                             }\n//                         }\n//\n//                         break;\n//                     case EventType.MouseDown when @event.button == 1:\n//                         var menu = new GenericMenu();\n//                         if (whiteArea.Contains(@event.mousePosition))\n//                         {\n//                             menu.AddItem(new GUIContent(\"Clear All [WHITE LIST]\"),\n//                                 false,\n//                                 () =>\n//                                 {\n//                                     LevelSystemEditorSetting.Instance.whitelistPaths.Clear();\n//                                     SaveLevelSystemSetting();\n//                                     RefreshAll();\n//                                 });\n//                         }\n//                         else if (blackArea.Contains(@event.mousePosition))\n//                         {\n//                             menu.AddItem(new GUIContent(\"Clear All [BLACK LIST]\"),\n//                                 false,\n//                                 () =>\n//                                 {\n//                                     LevelSystemEditorSetting.Instance.blacklistPaths.Clear();\n//                                     SaveLevelSystemSetting();\n//                                     RefreshAll();\n//                                 });\n//                         }\n//\n//                         menu.ShowAsContext();\n//                         break;\n//                 }\n//\n//                 EditorGUILayout.EndHorizontal();\n//\n//                 #endregion\n//\n//\n//                 #region horizontal\n//\n//                 EditorGUILayout.BeginHorizontal();\n//\n//                 #region vertical scope\n//\n//                 using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 10)))\n//                 {\n//                     if (LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0)\n//                     {\n//                         EditorGUILayout.LabelField(new GUIContent(\"\"), GUILayout.Width(width - 50),\n//                             GUILayout.Height(0));\n//                     }\n//                     else\n//                     {\n//                         GUILayout.Space(2);\n//                         _whiteScrollPosition = GUILayout.BeginScrollView(_whiteScrollPosition,\n//                             false, false, GUILayout.Height(250));\n//                         foreach (string t in LevelSystemEditorSetting.Instance.whitelistPaths\n//                                      .ToList())\n//                         {\n//                             DrawRow(t,\n//                                 width,\n//                                 _ =>\n//                                 {\n//                                     LevelSystemEditorSetting.Instance.whitelistPaths.Remove(_);\n//                                     SaveLevelSystemSetting();\n//                                 });\n//                         }\n//\n//                         GUILayout.EndScrollView();\n//                     }\n//                 }\n//\n//                 #endregion\n//\n//\n//                 GUILayout.Space(4);\n//\n//                 #region vertical scope\n//\n//                 using (var scope = new EditorGUILayout.VerticalScope(GUILayout.Width(width - 15)))\n//                 {\n//                     if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0)\n//                     {\n//                         EditorGUILayout.LabelField(new GUIContent(\"\"), GUILayout.Width(width - 50),\n//                             GUILayout.Height(0));\n//                     }\n//                     else\n//                     {\n//                         GUILayout.Space(2);\n//                         _blackScrollPosition = GUILayout.BeginScrollView(_blackScrollPosition,\n//                             false, false, GUILayout.Height(250));\n//                         foreach (string t in LevelSystemEditorSetting.Instance.blacklistPaths\n//                                      .ToList())\n//                         {\n//                             DrawRow(t,\n//                                 width,\n//                                 _ =>\n//                                 {\n//                                     LevelSystemEditorSetting.Instance.blacklistPaths.Remove(_);\n//                                     SaveLevelSystemSetting();\n//                                 });\n//                         }\n//\n//                         GUILayout.EndScrollView();\n//                     }\n//                 }\n//\n//                 #endregion\n//\n//\n//                 EditorGUILayout.EndHorizontal();\n//\n//                 #endregion\n//             }\n//\n//             void DrawRow(string content, float width, Action<string> action)\n//             {\n//                 #region horizontal\n//\n//                 EditorGUILayout.BeginHorizontal();\n//                 EditorGUILayout.LabelField(new GUIContent(content), GUILayout.Width(width - 100));\n//                 GUILayout.FlexibleSpace();\n//                 if (GUILayout.Button(Uniform.IconContent(\"d_scenevis_visible_hover\",\n//                         \"Ping Selection\")))\n//                 {\n//                     var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(content);\n//                     Selection.activeObject = obj;\n//                     EditorGUIUtility.PingObject(obj);\n//                 }\n//\n//                 if (GUILayout.Button(Uniform.IconContent(\"Toolbar Minus\", \"Remove\")))\n//                 {\n//                     action?.Invoke(content);\n//                     RefreshAll();\n//                 }\n//\n//                 EditorGUILayout.EndHorizontal();\n//\n//                 #endregion\n//             }\n//         }\n//\n//         private void ValidateWhitelist(string path, ref List<string> blackList)\n//         {\n//             foreach (string t in blackList.ToList())\n//             {\n//                 if (path.Equals(t)) blackList.Remove(t);\n//             }\n//         }\n//\n//         private void ValidateBlacklist(string path, ref List<string> whiteList)\n//         {\n//             foreach (string t in whiteList.ToList())\n//             {\n//                 if (path.Equals(t) || IsChildOfPath(t, path)) whiteList.Remove(t);\n//             }\n//         }\n//\n//         private void AddToWhitelist(string path)\n//         {\n//             var check = false;\n//             foreach (string whitePath in LevelSystemEditorSetting.Instance.whitelistPaths)\n//             {\n//                 if (IsChildOfPath(path, whitePath)) check = true;\n//             }\n//\n//             if (!check) LevelSystemEditorSetting.Instance.whitelistPaths.Add(path);\n//             LevelSystemEditorSetting.Instance.whitelistPaths = LevelSystemEditorSetting.Instance\n//                 .whitelistPaths.Distinct().ToList(); //unique\n//             SaveLevelSystemSetting();\n//         }\n//\n//         private void AddToBlacklist(string path)\n//         {\n//             var check = false;\n//             foreach (string blackPath in LevelSystemEditorSetting.Instance.blacklistPaths)\n//             {\n//                 if (IsChildOfPath(path, blackPath)) check = true;\n//             }\n//\n//             if (!check) LevelSystemEditorSetting.Instance.blacklistPaths.Add(path);\n//             LevelSystemEditorSetting.Instance.blacklistPaths = LevelSystemEditorSetting.Instance\n//                 .blacklistPaths.Distinct().ToList(); //unique\n//             SaveLevelSystemSetting();\n//         }\n//\n//         // return true if child is childrent of parent\n//         private bool IsChildOfPath(string child, string parent)\n//         {\n//             if (child.Equals(parent)) return false;\n//             var allParent = new List<DirectoryInfo>();\n//             GetAllParentDirectories(new DirectoryInfo(child), ref allParent);\n//\n//             foreach (var p in allParent)\n//             {\n//                 bool check = EqualPath(p, parent);\n//                 if (check) return true;\n//             }\n//\n//             return false;\n//         }\n//\n//         private void GetAllParentDirectories(DirectoryInfo directoryToScan,\n//             ref List<DirectoryInfo> directories)\n//         {\n//             while (true)\n//             {\n//                 if (directoryToScan == null || directoryToScan.Name == directoryToScan.Root.Name ||\n//                     !directoryToScan.FullName.Contains(\"Assets\")) return;\n//\n//                 directories.Add(directoryToScan);\n//                 directoryToScan = directoryToScan.Parent;\n//             }\n//         }\n//\n//         private bool EqualPath(FileSystemInfo info, string str)\n//         {\n//             string relativePath = info.FullName;\n//             if (relativePath.StartsWith(Application.dataPath.Replace('/', '\\\\')))\n//                 relativePath = \"Assets\" + relativePath.Substring(Application.dataPath.Length);\n//             relativePath = relativePath.Replace('\\\\', '/');\n//             return str.Equals(relativePath);\n//         }\n//\n//         private void ReduceScopeDirectory(ref List<string> source)\n//         {\n//             var arr = new string[source.Count];\n//             source.CopyTo(arr);\n//             var valueRemove = new List<string>();\n//             var unique = arr.Distinct().ToList();\n//             foreach (string u in unique)\n//             {\n//                 var check = false;\n//                 foreach (string k in unique)\n//                 {\n//                     if (IsChildOfPath(u, k)) check = true;\n//                 }\n//\n//                 if (check) valueRemove.Add(u);\n//             }\n//\n//             foreach (string i in valueRemove)\n//             {\n//                 unique.Remove(i);\n//             }\n//\n//             source = unique;\n//         }\n//\n//         private void InternalDrawSetting()\n//         {\n//             Uniform.DrawGroupFoldout(\"level_editor_config\", \"Setting\", DrawSetting);\n//\n//             void DrawSetting()\n//             {\n//                 _selectedSpawn =\n//                     EditorGUILayout.Popup(\"Where Spawn\", _selectedSpawn, _optionsSpawn);\n//                 if (EditorGUI.EndChangeCheck())\n//                 {\n//                     switch (_optionsSpawn[_selectedSpawn].ToLower())\n//                     {\n//                         case \"default\":\n//                             break;\n//                         case \"index\":\n//                             var currentPrefabState = GetCurrentPrefabStage();\n//                             if (currentPrefabState != null)\n//                             {\n//                                 _rootIndexSpawn = EditorGUILayout.IntField(\n//                                     new GUIContent(\"Index spawn\", \"Index from root stage contex\"),\n//                                     _rootIndexSpawn);\n//                             }\n//                             else\n//                             {\n//                                 EditorGUILayout.HelpBox(\"Index spawn only work in PrefabMode!\",\n//                                     MessageType.Warning);\n//                             }\n//\n//                             break;\n//                         case \"custom\":\n//                             _rootSpawn = (GameObject)EditorGUILayout.ObjectField(\n//                                 \"Spawn in GO here -->\", _rootSpawn, typeof(GameObject), true);\n//                             break;\n//                     }\n//                 }\n//\n//                 _selectedMode = EditorGUILayout.Popup(\"Mode\", _selectedMode, _optionsMode);\n//                 if (EditorGUI.EndChangeCheck())\n//                 {\n//                     switch (_optionsMode[_selectedMode].ToLower())\n//                     {\n//                         case \"renderer\":\n//                             EditorGUILayout.HelpBox(\"Based on Renderer detection\",\n//                                 MessageType.Info);\n//                             break;\n//                         case \"ignore\":\n//                             EditorGUILayout.HelpBox(\n//                                 \"GameObject will be spawn correcty at raycast location\\nIgnore calculate bound object\",\n//                                 MessageType.Info);\n//                             break;\n//                     }\n//                 }\n//             }\n//         }\n//\n//         private void InternalDrawPickupArea()\n//         {\n//             float height = 0f;\n//             Uniform.DrawGroupFoldoutWithRightClick(\"level_editor_pickup_area\", \"Pickup Area\",\n//                 DrawPickupArea, ShowMenuRefresh);\n//\n//             void DrawPickupArea()\n//             {\n//                 var tex = LevelEditor.GetPreview(_currentPickObject?.pickedObject);\n//                 if (tex)\n//                 {\n//                     string pickObjectName = _currentPickObject?.pickedObject.name;\n//\n//                     #region horizontal\n//\n//                     EditorGUILayout.BeginHorizontal();\n//                     GUILayout.Space(position.width / 2 - 50);\n//                     if (_editorInpsectorPreview == null || _previousObjectInpectorPreview !=\n//                         _currentPickObject?.pickedObject)\n//                     {\n//                         _editorInpsectorPreview =\n//                             UnityEditor.Editor.CreateEditor(_currentPickObject?.pickedObject);\n//                     }\n//\n//                     var rect = GUILayoutUtility.GetLastRect();\n//                     _editorInpsectorPreview.DrawPreview(new Rect(\n//                         new Vector2(position.width / 2 - 50, rect.position.y),\n//                         new Vector2(100, 100)));\n//                     _previousObjectInpectorPreview = _currentPickObject?.pickedObject;\n//                     GUI.color = new Color(1, 1, 1, 0f);\n//                     if (GUILayout.Button(tex, GUILayout.Height(80), GUILayout.Width(80)))\n//                     {\n//                     }\n//\n//                     GUI.color = Color.white;\n//                     EditorGUILayout.EndHorizontal();\n//\n//                     #endregion\n//\n//\n//                     EditorGUILayout.LabelField(\n//                         $\"Selected: <color=#80D2FF>{pickObjectName}</color>\\nPress Icon Again Or Escape Key To Deselect\",\n//                         new GUIStyle(EditorStyles.label) { richText = true },\n//                         GUILayout.Height(40));\n//                     height -= 128;\n//                     EditorGUILayout.HelpBox(\"Shift + Click To Add\", MessageType.Info);\n//                 }\n//                 else\n//                 {\n//                     EditorGUILayout.HelpBox(\"Select An Object First\", MessageType.Info);\n//                 }\n//\n//                 height -= 100;\n//                 if (Uniform.GetFoldoutState(\"level_editor_drop_area\"))\n//                 {\n//                     if (LevelSystemEditorSetting.Instance.blacklistPaths.Count == 0 &&\n//                         LevelSystemEditorSetting.Instance.whitelistPaths.Count == 0)\n//                     {\n//                         height -= 94;\n//                     }\n//                     else\n//                     {\n//                         height -= 342;\n//                     }\n//                 }\n//                 else\n//                 {\n//                     height -= 33;\n//                 }\n//\n//                 if (Uniform.GetFoldoutState(\"level_editor_config\"))\n//                 {\n//                     switch (_optionsSpawn[_selectedSpawn].ToLower())\n//                     {\n//                         case \"default\":\n//                             height -= 122;\n//                             break;\n//                         case \"index\":\n//                             var currentPrefabState = GetCurrentPrefabStage();\n//                             if (currentPrefabState != null)\n//                             {\n//                                 height -= 146;\n//                             }\n//                             else\n//                             {\n//                                 height -= 162;\n//                             }\n//\n//                             break;\n//                         case \"custom\":\n//                             height -= 146;\n//                             break;\n//                     }\n//                 }\n//                 else\n//                 {\n//                     height -= 33;\n//                 }\n//\n//                 var h = position.height + height;\n//\n//                 _pickObjectScrollPosition =\n//                     GUILayout.BeginScrollView(_pickObjectScrollPosition, GUILayout.Height(h));\n//                 var resultSplitGroupObjects =\n//                     PickObjects.GroupBy(_ => _.group).Select(_ => _.ToList()).ToList();\n//                 foreach (var splitGroupObject in resultSplitGroupObjects)\n//                 {\n//                     string nameGroup = splitGroupObject[0].group.ToUpper();\n//                     Uniform.DrawGroupFoldout($\"level_editor_pickup_area_child_{nameGroup}\",\n//                         nameGroup, () => DrawInGroup(splitGroupObject));\n//                 }\n//\n//                 GUILayout.EndScrollView();\n//             }\n//\n//             void DrawInGroup(IReadOnlyList<PickObject> pickObjectsInGroup)\n//             {\n//                 const int spacing = 25;\n//                 var counter = 0;\n//                 CalculateIdealCount(position.width - 50,\n//                     60,\n//                     135,\n//                     spacing,\n//                     5,\n//                     out int count,\n//                     out float size);\n//                 count = Mathf.Max(1, count);\n//                 while (counter >= 0 && counter < pickObjectsInGroup.Count)\n//                 {\n//                     EditorGUILayout.BeginHorizontal();\n//                     GUILayout.Space(8);\n//                     for (var x = 0; x < count; x++)\n//                     {\n//                         var pickObj = pickObjectsInGroup[counter];\n//                         var go = pickObj.pickedObject;\n//                         var tex = LevelEditor.GetPreview(go);\n//                         if (pickObj == _currentPickObject)\n//                         {\n//                             GUI.color = new Color32(79, 213, 255, 255);\n//                         }\n//                         else\n//                         {\n//                             GUI.color = Color.white;\n//                         }\n//\n//                         if (GUILayout.Button(new GUIContent(\"\"), GUILayout.Width(size),\n//                                 GUILayout.Height(size)))\n//                         {\n//                             if (Event.current.button == 1)\n//                             {\n//                                 ShowMenuRightClickItem(pickObj);\n//                             }\n//                             else\n//                             {\n//                                 _currentPickObject = _currentPickObject == pickObj ? null : pickObj;\n//                             }\n//                         }\n//\n//                         Rect Grown(Rect r, Vector2 half)\n//                         {\n//                             return new Rect(r.position - half, r.size + half * 2);\n//                         }\n//\n//                         GUI.color = Color.white;\n//                         var rect = GUILayoutUtility.GetLastRect();\n//                         if (tex)\n//                             GUI.DrawTexture(Grown(rect, Vector2.one * -10), tex,\n//                                 ScaleMode.ScaleToFit);\n//                         if (go)\n//                         {\n//                             EditorGUI.LabelField(Grown(rect, new Vector2(0, 15)), go.name,\n//                                 new GUIStyle(EditorStyles.miniLabel)\n//                                     { alignment = TextAnchor.LowerCenter, });\n//                         }\n//\n//                         counter++;\n//                         if (counter >= pickObjectsInGroup.Count) break;\n//                         GUILayout.Space(4);\n//                     }\n//\n//                     GUILayout.FlexibleSpace();\n//                     EditorGUILayout.EndHorizontal();\n//                     GUILayout.Space(spacing);\n//                 }\n//             }\n//\n//             void ShowMenuRefresh()\n//             {\n//                 var menu = new GenericMenu();\n//                 menu.AddItem(new GUIContent(\"Refresh Pickup  Area\"),\n//                     false,\n//                     () =>\n//                     {\n//                         _currentPickObject = null;\n//                         RefreshAll();\n//                     });\n//                 menu.ShowAsContext();\n//             }\n//\n//             void ShowMenuRightClickItem(PickObject pickObj)\n//             {\n//                 var menu = new GenericMenu();\n//                 menu.AddItem(new GUIContent(\"Ignore\"), false, () => IgnorePath(pickObj));\n//                 menu.AddItem(new GUIContent(\"Ping\"),\n//                     false,\n//                     () =>\n//                     {\n//                         Selection.activeObject = pickObj.pickedObject;\n//                         EditorGUIUtility.PingObject(pickObj.pickedObject);\n//                     });\n//                 menu.ShowAsContext();\n//             }\n//\n//             void IgnorePath(PickObject pickObj)\n//             {\n//                 var path = AssetDatabase.GetAssetPath(pickObj.pickedObject);\n//                 ValidateBlacklist(path, ref LevelSystemEditorSetting.Instance.whitelistPaths);\n//                 AddToBlacklist(path);\n//                 ReduceScopeDirectory(ref LevelSystemEditorSetting.Instance.blacklistPaths);\n//                 RefreshAll();\n//             }\n//         }\n//\n//         private void SaveLevelSystemSetting()\n//         {\n//             EditorUtility.SetDirty(LevelSystemEditorSetting.Instance);\n//             AssetDatabase.SaveAssets();\n//         }\n//\n//         private void OnSceneGUI(SceneView sceneView)\n//         {\n//             if (TryClose()) return;\n//             if (CheckEscape()) return;\n//             TryFakeRender(sceneView);\n//         }\n//\n//         private void TryFakeRender(SceneView sceneView)\n//         {\n//             var e = Event.current;\n//             if (!e.shift)\n//             {\n//                 if (_previewPickupObject != null) DestroyImmediate(_previewPickupObject);\n//                 return;\n//             }\n//\n//             if (_currentPickObject == null || !_currentPickObject.pickedObject) return;\n//             Vector3 mousePosition;\n//             Vector3 normal;\n//             if (sceneView.in2DMode)\n//             {\n//                 bool state = EditorExtend.Get2DMouseScenePosition(out var mousePosition2d);\n//                 mousePosition = mousePosition2d;\n//                 if (!state) return;\n//                 EditorExtend.FakeRenderSprite(_currentPickObject.pickedObject, mousePosition,\n//                     Vector3.one, Quaternion.identity);\n//                 SceneView.RepaintAll();\n//\n//                 if (e.type == EventType.MouseDown && e.button == 0)\n//                 {\n//                     AddPickObject(_currentPickObject, mousePosition);\n//                     EditorExtend.SkipEvent();\n//                 }\n//             }\n//             else\n//             {\n//                 var pos = EditorExtend.GetInnerGuiPosition(sceneView);\n//                 RaycastHit? raycastHit;\n//                 if (pos.Contains(e.mousePosition))\n//                 {\n//                     var currentPrefabState = GetCurrentPrefabStage();\n//                     if (currentPrefabState != null)\n//                     {\n//                         var (mouseCast, hitInfo) = RaycastPoint(GetParent(), EventMousePoint);\n//                         mousePosition = mouseCast;\n//                         normal = hitInfo.HasValue ? hitInfo.Value.normal : Vector3.up;\n//                         raycastHit = hitInfo;\n//                     }\n//                     else\n//                     {\n//                         Probe.Pick(ProbeFilter.Default,\n//                             sceneView,\n//                             e.mousePosition,\n//                             out mousePosition,\n//                             out normal);\n//                         raycastHit = null;\n//                     }\n//\n//                     float discSize = HandleUtility.GetHandleSize(mousePosition) * 0.4f;\n//                     Handles.color = new Color(1, 0, 0, 0.5f);\n//                     Handles.DrawSolidDisc(mousePosition, normal, discSize * 0.5f);\n//\n//                     if (!_previewPickupObject)\n//                     {\n//                         _previewPickupObject =\n//                             (GameObject)PrefabUtility.InstantiatePrefab(_currentPickObject\n//                                 ?.pickedObject);\n//                         StageUtility.PlaceGameObjectInCurrentStage(_previewPickupObject);\n//                         _previewPickupObject.hideFlags = HideFlags.HideAndDontSave;\n//                         _previewPickupObject.layer = LayerMask.NameToLayer(\"Ignore Raycast\");\n//                     }\n//\n// #pragma warning disable CS8321\n//                     void SetPosition2()\n//                     {\n//                         var rendererAttach = _currentPickObject?.pickedObject\n//                             .GetComponentInChildren<Renderer>();\n//                         if (raycastHit == null || rendererAttach == null) return;\n//                         var rendererOther = raycastHit.Value.collider.transform\n//                             .GetComponentInChildren<Renderer>();\n//                         if (rendererOther == null) return;\n//                         _previewPickupObject.transform.position = GetSpawnPosition(rendererAttach,\n//                             rendererOther, raycastHit.Value);\n//                     }\n// #pragma warning restore CS8321\n//\n//                     void SetPosition()\n//                     {\n//                         _previewPickupObject.transform.position = mousePosition;\n//\n//                         switch (_optionsMode[_selectedMode].ToLower())\n//                         {\n//                             case \"renderer\":\n//                                 if (_previewPickupObject.CalculateBounds(out var bounds,\n//                                         Space.World,\n//                                         true,\n//                                         false,\n//                                         false,\n//                                         false))\n//                                 {\n//                                     float difference = 0;\n//\n//                                     if (normal == Vector3.up || normal == Vector3.down)\n//                                     {\n//                                         difference = mousePosition.y - bounds.min.y;\n//                                     }\n//                                     else if (normal == Vector3.right || normal == Vector3.left)\n//                                     {\n//                                         difference = mousePosition.x - bounds.min.x;\n//                                     }\n//                                     else if (normal == Vector3.forward || normal == Vector3.back)\n//                                     {\n//                                         difference = mousePosition.z - bounds.min.z;\n//                                     }\n//\n//                                     _previewPickupObject.transform.position += difference * normal;\n//                                 }\n//\n//                                 break;\n//                             case \"ignore\":\n//                                 break;\n//                         }\n//                     }\n//\n//                     SetPosition();\n//\n//                     if (e.type == EventType.MouseDown && e.button == 0 && _previewPickupObject)\n//                     {\n//                         AddPickObject(_currentPickObject, _previewPickupObject.transform.position);\n//                         EditorExtend.SkipEvent();\n//                     }\n//                 }\n//             }\n//         }\n//\n//         /// <summary>\n//         /// only use when determined root\n//         /// </summary>\n//         /// <param name=\"root\"></param>\n//         /// <param name=\"ray\"></param>\n//         /// <param name=\"point\"></param>\n//         /// <returns></returns>\n//         private (bool, RaycastHit?) RayCast(Component root, Ray ray, out Vector3 point)\n//         {\n//             point = Vector3.zero;\n//             if (root.gameObject.scene.GetPhysicsScene()\n//                 .Raycast(ray.origin, ray.direction, out var hit))\n//             {\n//                 point = hit.point;\n//                 return (true, hit);\n//             }\n//\n//             return (false, null);\n//         }\n//\n//         /// <summary>\n//         /// only use when determined root\n//         /// </summary>\n//         /// <param name=\"root\"></param>\n//         /// <param name=\"screenPoint\"></param>\n//         /// <param name=\"distance\"></param>\n//         /// <returns></returns>\n//         private (Vector3, RaycastHit?) RaycastPoint(Component root, Vector2 screenPoint,\n//             float distance = 20)\n//         {\n//             var ray = SceneView.currentDrawingSceneView.camera.ScreenPointToRay(screenPoint);\n//             var result = RayCast(root, ray, out var point);\n//             if (!result.Item1)\n//             {\n//                 point = ray.origin + ray.direction.normalized * distance;\n//             }\n//\n//             return (point, result.Item2);\n//         }\n//\n//         /// <summary>\n//         /// for mesh with irregular shape the returned result is incorrect\n//         /// missing some direction\n//         /// </summary>\n//         /// <param name=\"rendererAttach\"></param>\n//         /// <param name=\"rendererOther\"></param>\n//         /// <param name=\"hitInfo\"></param>\n//         /// <returns></returns>\n//         private Vector3 GetSpawnPosition(Renderer rendererAttach, Renderer rendererOther,\n//             RaycastHit hitInfo)\n//         {\n//             var boundsAttach = rendererAttach.bounds;\n//             var boundsOther = rendererOther.bounds;\n//\n//             var otherPos = hitInfo.collider.gameObject.transform.position;\n//             var pointPos = hitInfo.point;\n//\n//             int isSpawnRighSide;\n//             if (Mathf.Abs(otherPos.x - pointPos.x) >= boundsOther.size.x / 2)\n//             {\n//                 isSpawnRighSide = otherPos.x > pointPos.x ? -1 : 1;\n//             }\n//             else\n//             {\n//                 isSpawnRighSide = 0;\n//             }\n//\n//             int isSpawnUpSide;\n//             if (Mathf.Abs(otherPos.y - pointPos.y) >= boundsOther.size.y / 2)\n//             {\n//                 isSpawnUpSide = otherPos.y > pointPos.y ? -1 : 1;\n//             }\n//             else\n//             {\n//                 isSpawnUpSide = 0;\n//             }\n//\n//             int isSpawnForwardSide;\n//             if (Mathf.Abs(otherPos.z - pointPos.z) >= boundsOther.size.z / 2)\n//             {\n//                 isSpawnForwardSide = otherPos.z > pointPos.z ? -1 : 1;\n//             }\n//             else\n//             {\n//                 isSpawnForwardSide = 0;\n//             }\n//\n//             return new Vector3(hitInfo.point.x + (boundsAttach.size.x / 2 * isSpawnRighSide),\n//                 hitInfo.point.y + (boundsAttach.size.y / 2 * isSpawnUpSide),\n//                 hitInfo.point.z + (boundsAttach.size.z / 2 * isSpawnForwardSide));\n//         }\n//\n//         /// <summary>\n//         /// Spawn pickup object\n//         /// </summary>\n//         /// <param name=\"pickObject\"></param>\n//         /// <param name=\"worldPos\"></param>\n//         private void AddPickObject(PickObject pickObject, Vector3 worldPos)\n//         {\n//             if (pickObject?.pickedObject)\n//             {\n//                 var inst =\n//                     (GameObject)PrefabUtility.InstantiatePrefab(pickObject.pickedObject,\n//                         GetParent());\n//                 inst.transform.position = worldPos;\n//                 Undo.RegisterCreatedObjectUndo(inst.gameObject, \"Create pick obj\");\n//                 Selection.activeObject = inst;\n//             }\n//         }\n//\n//         private Transform GetParent()\n//         {\n//             Transform parent = null;\n//             var currentPrefabState = GetCurrentPrefabStage();\n//\n//             if (currentPrefabState != null)\n//             {\n//                 var prefabRoot = currentPrefabState.prefabContentsRoot.transform;\n//                 switch (_optionsSpawn[_selectedSpawn].ToLower())\n//                 {\n//                     case \"default\":\n//                         parent = prefabRoot;\n//                         break;\n//                     case \"index\":\n//                         if (_rootIndexSpawn < 0) parent = prefabRoot;\n//                         else if (prefabRoot.childCount - 1 > _rootIndexSpawn)\n//                             parent = prefabRoot.GetChild(_rootIndexSpawn);\n//                         else parent = prefabRoot;\n//                         break;\n//                     case \"custom\":\n//                         parent = _rootSpawn ? _rootSpawn.transform : prefabRoot;\n//                         break;\n//                 }\n//             }\n//             else\n//             {\n//                 switch (_optionsSpawn[_selectedSpawn].ToLower())\n//                 {\n//                     case \"default\":\n//                     case \"index\":\n//                         parent = null;\n//                         break;\n//                     case \"custom\":\n//                         parent = _rootSpawn ? _rootSpawn.transform : null;\n//                         break;\n//                 }\n//             }\n//\n//             return parent;\n//         }\n//\n//         private PrefabStage GetCurrentPrefabStage()\n//         {\n//             return PrefabStageUtility.GetCurrentPrefabStage();\n//         }\n//\n//         /// <summary>\n//         /// Calculate count item pickup can display\n//         /// </summary>\n//         /// <param name=\"availableSpace\"></param>\n//         /// <param name=\"minSize\"></param>\n//         /// <param name=\"maxSize\"></param>\n//         /// <param name=\"spacing\"></param>\n//         /// <param name=\"defaultCount\"></param>\n//         /// <param name=\"count\"></param>\n//         /// <param name=\"size\"></param>\n//         /// <returns></returns>\n//         // ReSharper disable once UnusedMethodReturnValue.Local\n//         private static bool CalculateIdealCount(float availableSpace, float minSize, float maxSize,\n//             float spacing, int defaultCount, out int count, out float size)\n//         {\n//             float halfSpacing = spacing / 2f;\n//             int minCount = Mathf.FloorToInt(availableSpace / (maxSize + halfSpacing));\n//             int maxCount = Mathf.FloorToInt(availableSpace / (minSize + halfSpacing));\n//             bool goodness = defaultCount >= minCount && defaultCount <= maxCount;\n//             count = Mathf.Clamp(defaultCount, minCount, maxCount);\n//             size = (availableSpace - halfSpacing * (count - 1) - (count - 1) * (count / 10f)) /\n//                    count;\n//             return goodness;\n//         }\n//\n//         private void ClearEditor()\n//         {\n//             Repaint();\n//         }\n    }\n}"
  },
  {
    "path": "VirtueSky/LevelEditor/LevelEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 732ddfe59241fd34ab461578cb96db31\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/LevelEditor/LevelSystemEditorSetting.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.LevelEditor\n{\n    [Serializable]\n    public class LevelSystemEditorSetting : ScriptableSettings<LevelSystemEditorSetting>\n    {\n        public List<string> whitelistPaths = new List<string>();\n        public List<string> blacklistPaths = new List<string>();\n        public readonly string[] optionsSpawn = { \"Default\", \"Index\", \"Custom\" };\n        public readonly string[] optionsMode = { \"Renderer\", \"Ignore\" };\n\n        public Vector2 SettingTabScrollPosition { get; set; } = Vector2.zero;\n        public Vector2 PickObjectScrollPosition { get; set; } = Vector2.zero;\n        public Vector2 WhitelistScrollPosition { get; set; }\n        public Vector2 BlacklistScrollPosition { get; set; }\n        public PickObject CurrentPickObject { get; set; }\n        public List<PickObject> PickObjects { get; set; } = new List<PickObject>();\n        public SerializedObject _pathFolderSerializedObject;\n        public SerializedProperty _pathFolderProperty;\n        public int SelectedSpawn { get; set; }\n        public int SelectedMode { get; set; }\n        public GameObject RootSpawn { get; set; }\n        public int RootIndexSpawn { get; set; }\n        public GameObject PreviewPickupObject { get; set; }\n        public UnityEngine.Object PreviousObjectInspectorPreview { get; set; }\n        public UnityEditor.Editor EditorInspectorPreview { get; set; }\n    }\n\n    public enum LevelEditorTabType\n    {\n        Setting,\n        Pickup\n    }\n\n    public static class UtilitiesLevelSystemDrawer\n    {\n        // [MenuItem(\"Sunflower/LevelEditor &3\")]\n        // public static void OpenLevelEditor()\n        // {\n        //     OnInspectorGUI();\n        // }\n\n        // public static void OnInspectorGUI()\n        // {\n        //     var scriptableSetting = Resources.Load<LevelSystemEditorSetting>(nameof(LevelSystemEditorSetting));\n        //     if (scriptableSetting == null)\n        //     {\n        //         GUI.enabled = !EditorApplication.isCompiling;\n        //         GUI.backgroundColor = Uniform.Pink;\n        //         var setting = ScriptableObject.CreateInstance<LevelSystemEditorSetting>();\n        //         const string path = \"Assets/_Sunflower/Editor/Resources\";\n        //         if (!Directory.Exists(path)) Directory.CreateDirectory(path);\n        //         AssetDatabase.CreateAsset(setting, $\"{path}/{nameof(LevelSystemEditorSetting)}.asset\");\n        //         RegistryManager.Add(\"com.unity.addressables\", \"1.21.19\");\n        //         RegistryManager.Resolve();\n        //         AssetDatabase.SaveAssets();\n        //         AssetDatabase.Refresh();\n        //         Debug.Log(\n        //             $\"{nameof(LevelSystemEditorSetting)} was created ad {path}/{nameof(LevelSystemEditorSetting)}.asset\");\n        //         GUI.backgroundColor = Color.white;\n        //         GUI.enabled = true;\n        //\n        //         OpenWindowLevelEditor();\n        //     }\n        //     else\n        //     {\n        //         OpenWindowLevelEditor();\n        //     }\n        // }\n        //\n        // static void OpenWindowLevelEditor()\n        // {\n        //     var window = EditorWindow.GetWindow<LevelEditor>(\"Level Editor\", true);\n        //     if (window)\n        //     {\n        //         window.minSize = new Vector2(275, 0);\n        //         window.Show(true);\n        //     }\n        // }\n    }\n}"
  },
  {
    "path": "VirtueSky/LevelEditor/LevelSystemEditorSetting.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2cf7fd915596441e97e1ada0052356b4\ntimeCreated: 1697171875"
  },
  {
    "path": "VirtueSky/LevelEditor/PickObject.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.LevelEditor\n{\n    public class PickObject\n    {\n        public string group;\n        public GameObject pickedObject;\n    }\n}"
  },
  {
    "path": "VirtueSky/LevelEditor/PickObject.cs.meta",
    "content": "fileFormatVersion: 2\nguid: abcdf4f25e5d48ad87be9afa4e129744\ntimeCreated: 1707213556"
  },
  {
    "path": "VirtueSky/LevelEditor/PreviewGenerator.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.LevelEditor\n{\n    public class PreviewGenerator\n    {\n        public static readonly PreviewGenerator Default = new PreviewGenerator();\n\n        private const int MAX_TEXTURE_SIZE = 2048;\n        private static int latePreviewQueued;\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public Vector3 previewPosition = new Vector3(9999, 9999, -9999);\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public Vector3 latePreviewOffset = new Vector3(100, 100, 0);\n\n        public bool transparentBackground = true;\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public Color solidBackgroundColor = new Color(0.3f, 0.3f, 0.3f);\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public FilterMode imageFilterMode = FilterMode.Point;\n        public ImageSizeType sizingType = ImageSizeType.PixelsPerUnit;\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public int pixelPerUnit = 32;\n        public int width = 256;\n        public int height = 256;\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public float timingCounter = 1;\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public Action<Texture2D> onCapturedCallback;\n\n        // ReSharper disable once MemberCanBePrivate.Global\n        public Action<GameObject> onPreCaptureCallback;\n\n\n        public enum ImageSizeType\n        {\n            PixelsPerUnit,\n            Fit,\n            Fill,\n            Stretch,\n        }\n\n        public PreviewGenerator Copy()\n        {\n            return new PreviewGenerator()\n            {\n                previewPosition = previewPosition,\n                latePreviewOffset = latePreviewOffset,\n                transparentBackground = transparentBackground,\n                solidBackgroundColor = solidBackgroundColor,\n                imageFilterMode = imageFilterMode,\n                sizingType = sizingType,\n                pixelPerUnit = pixelPerUnit,\n                width = width,\n                height = height,\n                timingCounter = timingCounter,\n                onCapturedCallback = onCapturedCallback,\n                onPreCaptureCallback = onPreCaptureCallback,\n            };\n        }\n\n        public PreviewGenerator OnCaptured(Action<Texture2D> callback)\n        {\n            onCapturedCallback = callback;\n            return this;\n        }\n\n        public PreviewGenerator OnPreCaptured(Action<GameObject> callback)\n        {\n            onPreCaptureCallback = callback;\n            return this;\n        }\n\n\n        public Texture2D CreatePreview(GameObject obj, bool clone = true)\n        {\n            if (!CanCreatePreview(obj))\n            {\n                onCapturedCallback?.Invoke(null);\n                return EditorResources.ScriptableFactory;\n            }\n\n            var cachedPosition = obj.transform.position;\n            var prevObj = clone ? Object.Instantiate(obj, null) : obj;\n            prevObj.transform.position = previewPosition + latePreviewQueued * latePreviewOffset;\n\n            var bounds = GetBounds<Renderer>(prevObj, false);\n            var size = GetImageSize(bounds);\n            var cam = CreatePreviewCamera(bounds);\n            var light = CreatePreviewLight(bounds);\n\n            latePreviewQueued++;\n            var dummy = new GameObject(\"Preview Dummy\");\n\n            void Callback()\n            {\n                latePreviewQueued--;\n                if (clone)\n                {\n                    Object.DestroyImmediate(prevObj);\n                }\n                else\n                {\n                    prevObj.transform.position = cachedPosition;\n                }\n\n                Object.DestroyImmediate(cam.gameObject);\n                Object.DestroyImmediate(light.gameObject);\n                Object.DestroyImmediate(dummy.gameObject);\n            }\n\n            return WrappedCapture(prevObj,\n                cam,\n                size.x,\n                size.y,\n                Callback);\n        }\n\n\n        private void NotifyPreviewTaking(GameObject go, Action<IPreviewComponent> action)\n        {\n            var allComps = go.GetComponentsInChildren<Component>();\n            foreach (var comp in allComps)\n            {\n                // ReSharper disable once SuspiciousTypeConversion.Global\n                if (comp is IPreviewComponent component) action?.Invoke(component);\n            }\n        }\n\n        private bool CanCreatePreview(GameObject obj)\n        {\n            return obj != null && obj.GetComponentsInChildren<Renderer>().Any(r => r != null && r.enabled);\n        }\n\n        private Camera CreatePreviewCamera(Bounds bounds)\n        {\n            var camObj = new GameObject(\"Preview generator camera\");\n            var cam = camObj.AddComponent<Camera>();\n\n            cam.transform.position = bounds.center + Vector3.back * (bounds.extents.z + 2);\n            cam.nearClipPlane = 0.01f;\n            cam.farClipPlane = bounds.size.z + 4;\n\n            cam.orthographic = true;\n            cam.orthographicSize = bounds.extents.y;\n            cam.aspect = bounds.extents.x / bounds.extents.y;\n\n            cam.clearFlags = CameraClearFlags.Color;\n            cam.backgroundColor = solidBackgroundColor;\n            if (transparentBackground) cam.backgroundColor *= 0;\n\n            cam.enabled = false;\n\n            return cam;\n        }\n\n        private Light CreatePreviewLight(Bounds bounds)\n        {\n            var lightObj = new GameObject(\"Preview generator light\");\n            var light = lightObj.AddComponent<Light>();\n\n            light.type = LightType.Directional;\n            light.transform.position = bounds.center + Vector3.back * (bounds.extents.z + 2);\n            light.color = Color.white;\n            light.intensity = 1;\n            return light;\n        }\n\n        private Vector2Int GetImageSize(Bounds bounds)\n        {\n            var w = 1;\n            var h = 1;\n\n            if (sizingType == ImageSizeType.PixelsPerUnit)\n            {\n                w = Mathf.CeilToInt(bounds.size.x * pixelPerUnit);\n                h = Mathf.CeilToInt(bounds.size.y * pixelPerUnit);\n            }\n            else if (sizingType == ImageSizeType.Stretch)\n            {\n                w = width;\n                h = height;\n            }\n            else if (sizingType == ImageSizeType.Fit || sizingType == ImageSizeType.Fill)\n            {\n                float widthFactor = width / bounds.size.x;\n                float heightFactor = height / bounds.size.y;\n                float factor = sizingType == ImageSizeType.Fit ? Mathf.Min(widthFactor, heightFactor) : Mathf.Max(widthFactor, heightFactor);\n\n                w = Mathf.CeilToInt(bounds.size.x * factor);\n                h = Mathf.CeilToInt(bounds.size.y * factor);\n            }\n\n            if (w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE)\n            {\n                float downscaleWidthFactor = (float)MAX_TEXTURE_SIZE / w;\n                float downscaleHeightFactor = (float)MAX_TEXTURE_SIZE / h;\n                float downscaleFactor = Mathf.Min(downscaleWidthFactor, downscaleHeightFactor);\n\n                w = Mathf.CeilToInt(w * downscaleFactor);\n                h = Mathf.CeilToInt(h * downscaleFactor);\n            }\n\n            return new Vector2Int(w, h);\n        }\n\n        private Texture2D WrappedCapture(GameObject obj, Camera cam, int w, int h, Action callback)\n        {\n            onPreCaptureCallback?.Invoke(obj);\n\n            NotifyPreviewTaking(obj, i => i.OnPreviewCapturing(this));\n            var tex = DoCapture(cam, w, h);\n            NotifyPreviewTaking(obj, i => i.OnPreviewCaptured(this));\n\n            callback?.Invoke();\n            onCapturedCallback?.Invoke(tex);\n\n            return tex;\n        }\n\n        private Texture2D DoCapture(Camera cam, int w, int h)\n        {\n            var temp = RenderTexture.active;\n            RenderTexture renderTex = null;\n            try\n            {\n                renderTex = RenderTexture.GetTemporary(w, h, 16);\n            }\n            catch (Exception)\n            {\n                //\n            }\n\n            RenderTexture.active = renderTex;\n\n            cam.enabled = true;\n            cam.targetTexture = renderTex;\n            cam.Render();\n            cam.targetTexture = null;\n            cam.enabled = false;\n\n            if (w <= 0) w = 512;\n            if (h <= 0) h = 512;\n            var tex = new Texture2D(w, h, transparentBackground ? TextureFormat.RGBA32 : TextureFormat.RGB24, false) { filterMode = imageFilterMode };\n            tex.ReadPixels(new Rect(0, 0, w, h), 0, 0, false);\n            tex.Apply(false, false);\n\n            RenderTexture.active = temp;\n            RenderTexture.ReleaseTemporary(renderTex);\n            return tex;\n        }\n\n        /// <summary>\n        /// Get bound of gameobject via collider or renderer\n        /// </summary>\n        /// <param name=\"go\"></param>\n        /// <param name=\"includeInactive\"></param>\n        /// <param name=\"getBounds\"></param>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        private Bounds GetBounds<T>(GameObject go, bool includeInactive = true, System.Func<T, Bounds> getBounds = null) where T : Component\n        {\n            if (getBounds == null)\n                getBounds = (t) => (t as Collider)?.bounds ?? (t as Collider2D)?.bounds ?? (t as Renderer)?.bounds ?? default;\n            var comps = go.GetComponentsInChildren<T>(includeInactive).Where(_ => !(_.gameObject.GetComponent<ParticleSystem>())).ToArray();\n\n            Bounds bound = default;\n            bool found = false;\n\n            foreach (var comp in comps)\n            {\n                if (comp)\n                {\n                    if (!includeInactive)\n                    {\n                        if (!(comp as Collider)?.enabled ?? false) continue;\n                        if (!(comp as Collider2D)?.enabled ?? false) continue;\n                        if (!(comp as Renderer)?.enabled ?? false) continue;\n                        if (!(comp as MonoBehaviour)?.enabled ?? false) continue;\n                    }\n\n                    if (!found || bound.size == Vector3.zero)\n                    {\n                        bound = getBounds(comp);\n                        found = true;\n                    }\n                    else bound.Encapsulate(getBounds(comp));\n                }\n            }\n\n            return bound;\n        }\n    }\n\n    internal interface IPreviewComponent\n    {\n        void OnPreviewCapturing(PreviewGenerator preview);\n\n        void OnPreviewCaptured(PreviewGenerator preview);\n    }\n}"
  },
  {
    "path": "VirtueSky/LevelEditor/PreviewGenerator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 916e32408cb546d5b9e85d4ee87e0281\ntimeCreated: 1697172001"
  },
  {
    "path": "VirtueSky/LevelEditor/Probe.cs",
    "content": "﻿namespace VirtueSky.LevelEditor\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Linq;\n    using UnityEditor;\n    using UnityEngine;\n\n    public delegate void ProbeHitSelectHandler(bool add);\n\n    public struct ProbeHit\n    {\n        public GameObject gameObject;\n\n        public Vector3? point;\n\n        public Vector3? normal;\n\n        public float? distance;\n\n        public string label;\n\n        public ProbeHitSelectHandler selectHandler;\n\n        public Action focusHandler;\n\n        public Action lostFocusHandler;\n\n        public Transform Transform\n        {\n            get => gameObject.transform;\n            set => gameObject = value.gameObject;\n        }\n\n        public RectTransform RectTransform\n        {\n            get => gameObject.GetComponent<RectTransform>();\n            set => gameObject = value.gameObject;\n        }\n\n        public GameObject groupGameObject;\n\n        public double groupOrder;\n\n        public ProbeHit(GameObject gameObject)\n        {\n            this.gameObject = gameObject;\n            this.groupGameObject = gameObject;\n            groupOrder = 0;\n            point = default;\n            normal = default;\n            distance = default;\n            label = default;\n            selectHandler = default;\n            focusHandler = default;\n            lostFocusHandler = default;\n        }\n\n        public void Select(bool add)\n        {\n            if (selectHandler != null)\n            {\n                selectHandler(add);\n            }\n            else if (gameObject != null)\n            {\n                if (add)\n                {\n                    Selection.objects = Selection.objects.Append(gameObject).ToArray();\n                }\n                else\n                {\n                    Selection.activeGameObject = gameObject;\n                }\n            }\n        }\n\n        public void OnFocusEnter()\n        {\n            if (focusHandler != null)\n            {\n                focusHandler.Invoke();\n            }\n            else\n            {\n                Probe.Highlight(gameObject);\n            }\n        }\n\n        public void OnFocusLeave()\n        {\n            if (lostFocusHandler != null)\n            {\n                lostFocusHandler.Invoke();\n            }\n            else\n            {\n                Probe.ClearHighlight();\n            }\n        }\n    }\n\n    public static class Probe\n    {\n        #region Object Picking\n\n        private const int DEFAULT_LIMIT = 100;\n\n        private static bool CanPickHandles =>\n            E != null && (E.type == EventType.MouseMove || E.type == EventType.MouseDown ||\n                          E.type == EventType.MouseUp || E.type == EventType.MouseDrag ||\n                          E.type == EventType.MouseEnterWindow || E.type == EventType.MouseLeaveWindow);\n\n        public static ProbeHit? Pick(ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, out Vector3 point)\n        {\n            var results = new List<ProbeHit>();\n\n            try\n            {\n                PickAllNonAlloc(results, filter, sceneView, guiPosition);\n\n                foreach (var result in results)\n                {\n                    if (result.point.HasValue)\n                    {\n                        point = result.point.Value;\n                        return result;\n                    }\n                }\n\n                point = DefaultPoint(sceneView, guiPosition);\n                return null;\n            }\n            finally\n            {\n                results = null;\n            }\n        }\n\n        public static ProbeHit? Pick(ProbeFilter filter, SceneView sceneView, Vector2 guiPosition, out Vector3 point,\n            out Vector3 normal)\n        {\n            var results = new List<ProbeHit>();\n\n            try\n            {\n                PickAllNonAlloc(results, filter, sceneView, guiPosition);\n\n                foreach (var result in results)\n                {\n                    if (result.point.HasValue && result.normal.HasValue)\n                    {\n                        point = result.point.Value;\n                        normal = result.normal.Value;\n                        return result;\n                    }\n                }\n\n                point = DefaultPoint(sceneView, guiPosition);\n                normal = Vector3.up;\n                return null;\n            }\n            finally\n            {\n                results = null;\n            }\n        }\n\n\n        public static ProbeHit[] PickAll(ProbeFilter filter, SceneView sceneView, Vector2 guiPosition,\n            int limit = DEFAULT_LIMIT)\n        {\n            var results = new List<ProbeHit>();\n            PickAllNonAlloc(results,\n                filter,\n                sceneView,\n                guiPosition,\n                limit);\n            return results.ToArray();\n        }\n\n        private static void PickAllNonAlloc(List<ProbeHit> hits, ProbeFilter filter, SceneView sceneView,\n            Vector2 guiPosition, int limit = DEFAULT_LIMIT)\n        {\n            var screenPosition = HandleUtility.GUIPointToScreenPixelCoordinate(guiPosition);\n            var ray3D = HandleUtility.GUIPointToWorldRay(guiPosition);\n            var worldPosition = sceneView.camera.ScreenToWorldPoint(screenPosition);\n            var layerMask = Physics.DefaultRaycastLayers;\n\n            var raycastHits = new RaycastHit[limit];\n            var overlapHits = new Collider2D[limit];\n            var handleHits = new HashSet<GameObject>();\n            var ancestorHits = new HashSet<ProbeHit>();\n            var gameObjectHits = new Dictionary<GameObject, ProbeHit>();\n\n            try\n            {\n                // Raycast (3D)\n                if (filter.Raycast)\n                {\n                    var raycastHitCount = Physics.RaycastNonAlloc(ray3D, raycastHits, Mathf.Infinity, layerMask);\n\n                    for (var i = 0; i < raycastHitCount; i++)\n                    {\n                        var raycastHit = raycastHits[i];\n\n#if UNITY_2019_2_OR_NEWER\n                        if (SceneVisibilityManager.instance.IsHidden(raycastHit.transform.gameObject))\n                        {\n                            continue;\n                        }\n#endif\n\n                        var gameObject = raycastHit.transform.gameObject;\n\n                        if (!gameObjectHits.TryGetValue(gameObject, out var hit))\n                        {\n                            hit = new ProbeHit(gameObject);\n                        }\n\n                        hit.point = raycastHit.point;\n                        hit.normal = raycastHit.normal;\n                        hit.distance = raycastHit.distance;\n\n                        gameObjectHits[gameObject] = hit;\n                    }\n                }\n\n                // Overlap (2D)\n                if (filter.Overlap)\n                {\n                    var overlapHitCount = Physics2D.OverlapPointNonAlloc(worldPosition, overlapHits, layerMask);\n\n                    for (var i = 0; i < overlapHitCount; i++)\n                    {\n                        var overlapHit = overlapHits[i];\n\n#if UNITY_2019_2_OR_NEWER\n                        if (SceneVisibilityManager.instance.IsHidden(overlapHit.transform.gameObject))\n                        {\n                            continue;\n                        }\n#endif\n\n                        var gameObject = overlapHit.transform.gameObject;\n\n                        if (!gameObjectHits.TryGetValue(gameObject, out var hit))\n                        {\n                            hit = new ProbeHit(gameObject);\n                        }\n\n                        hit.distance = hit.distance ?? Vector3.Distance(overlapHit.transform.position, worldPosition);\n\n                        gameObjectHits[gameObject] = hit;\n                    }\n                }\n\n                // Handles (Editor Default)\n                if (filter.Handles && CanPickHandles)\n                {\n                    PickAllHandlesNonAlloc(handleHits, guiPosition, limit);\n\n                    foreach (var handleHit in handleHits)\n                    {\n                        var gameObject = handleHit;\n\n                        if (!gameObjectHits.TryGetValue(gameObject, out var hit))\n                        {\n                            hit = new ProbeHit(gameObject);\n                        }\n\n                        hit.distance = hit.distance ?? Vector3.Distance(handleHit.transform.position, worldPosition);\n\n                        gameObjectHits[gameObject] = hit;\n                    }\n                }\n\n                // Ancestors\n                foreach (var gameObjectHit in gameObjectHits)\n                {\n                    var gameObject = gameObjectHit.Key;\n                    var hit = gameObjectHit.Value;\n\n                    var parent = gameObject.transform.parent;\n\n                    int depth = 0;\n\n                    while (parent != null)\n                    {\n                        var parentGameObject = parent.gameObject;\n\n                        var parentHit = new ProbeHit(parentGameObject);\n                        parentHit.groupGameObject = gameObject;\n                        parentHit.distance =\n                            hit.distance ?? Vector3.Distance(parentHit.Transform.position, worldPosition);\n                        parentHit.groupOrder = 1000 + depth;\n\n                        ancestorHits.Add(parentHit);\n\n                        parent = parent.parent;\n                        depth++;\n                    }\n                }\n\n                // Prepare final hits\n                hits.Clear();\n\n                // Add hits\n                foreach (var gameObjectHit in gameObjectHits.Values)\n                {\n                    hits.Add(gameObjectHit);\n                }\n\n                foreach (var ancestorHit in ancestorHits)\n                {\n                    hits.Add(ancestorHit);\n                }\n\n                // Sort by distance\n                hits.Sort(CompareHits);\n            }\n            finally\n            {\n                raycastHits = null;\n                overlapHits = null;\n\n                handleHits.Clear();\n                ancestorHits.Clear();\n                gameObjectHits.Clear();\n\n                handleHits = null;\n                ancestorHits = null;\n                gameObjectHits = null;\n            }\n        }\n\n        private static void PickAllHandlesNonAlloc(HashSet<GameObject> results, Vector2 position,\n            int limit = DEFAULT_LIMIT)\n        {\n            if (!CanPickHandles)\n            {\n                // HandleUtility.PickGameObject is not supported in those contexts\n                Debug.LogWarning($\"Cannot pick game objects in the current event: {E?.ToString() ?? \"null\"}\");\n                return;\n            }\n\n            GameObject result;\n\n            var count = 0;\n\n            do\n            {\n                var ignored = results.ToArray();\n\n                result = HandleUtility.PickGameObject(position, false, ignored);\n\n                // Ignored doesn't seem very reliable. Sometimes, an item included\n                // in ignored will still be returned. That's a sign we should stop.\n                if (results.Contains(result))\n                {\n                    result = null;\n                }\n\n                if (result != null)\n                {\n                    results.Add(result);\n                }\n            } while (result != null && count++ < limit);\n        }\n\n        private static readonly Comparison<ProbeHit> CompareHits = CompareProbeHit;\n\n        private static int CompareProbeHit(ProbeHit a, ProbeHit b)\n        {\n            var distanceA = a.distance ?? Mathf.Infinity;\n            var distanceB = b.distance ?? Mathf.Infinity;\n            return distanceA.CompareTo(distanceB);\n        }\n\n        private static Vector3 DefaultPoint(SceneView sceneView, Vector2 guiPosition)\n        {\n            var screenPosition = (Vector3)HandleUtility.GUIPointToScreenPixelCoordinate(guiPosition);\n            screenPosition.z = sceneView.cameraDistance;\n            return sceneView.camera.ScreenToWorldPoint(screenPosition);\n        }\n\n        #endregion\n\n        #region Scene View Integration\n\n        private static Event E => Event.current;\n\n        private static Vector2? pressPosition;\n        private static GameObject highlight;\n\n        internal static void Highlight(GameObject selection)\n        {\n            highlight = selection;\n            SceneView.RepaintAll();\n        }\n\n        internal static void ClearHighlight()\n        {\n            highlight = null;\n            SceneView.RepaintAll();\n        }\n\n        #endregion\n    }\n\n    public struct ProbeFilter\n    {\n        public bool Raycast { get; set; }\n        public bool Overlap { get; set; }\n        public bool Handles { get; set; }\n\n        public static ProbeFilter Default { get; } = new ProbeFilter { Raycast = true, Overlap = true, Handles = true };\n    }\n}"
  },
  {
    "path": "VirtueSky/LevelEditor/Probe.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1618f116123449a397a2fc8f647bb28e\ntimeCreated: 1697172426"
  },
  {
    "path": "VirtueSky/LevelEditor/virtuesky.sunflower.leveleditor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.LevelEditor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:0b6289df6f84a6f4b982ff72d23e0273\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/LevelEditor/virtuesky.sunflower.leveleditor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: b1979aef4cc42ae46af23ce2c4c109cc\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/LevelEditor.meta",
    "content": "fileFormatVersion: 2\nguid: 18624879c63c4603b36a29a52fd1f076\ntimeCreated: 1697171489"
  },
  {
    "path": "VirtueSky/Linq/Aggregate.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    /// <summary>\n    /// Provides faster array and list specific extension methods with\n    /// the same semantics as the Linq extensions methods.\n    /// </summary>\n    public static partial class L\n    {\n        // ------------------------------ Arrays --------------------------\n\n        /// <summary>\n        /// Applies an accumulator function over an array.\n        /// </summary>        \n        /// <param name=\"source\">An array to aggregate over.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <returns>The final accumulator value</returns>\n        public static TSource Reduce<TSource>(this TSource[] source, Func<TSource, TSource, TSource> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            TSource result = source[0];\n            for (int i = 1; i < source.Length; i++)\n            {\n                result = func(result, source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Applies an accumulator function over an array. The specified seed\n        /// value is used as the initial accumulator value.\n        /// </summary>        \n        /// <param name=\"source\">An array to aggregate over.</param>\n        /// <param name=\"seed\">The initial accumulator value.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <returns>The final accumulator value</returns>\n        public static TAccumulate Reduce<TSource, TAccumulate>(this TSource[] source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            TAccumulate result = seed;\n            foreach (var v in source)\n            {\n                result = func(result, v);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Applies an accumulator function over an array. The specified seed\n        /// value is used as the initial accumulator value, and the specified \n        /// function is used to select the result value.\n        /// </summary>        \n        /// <param name=\"source\">An array to aggregate over.</param>\n        /// <param name=\"seed\">The initial accumulator value.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <param name=\"resultSelector\">A function to transform the final accumulator value into the result value.</param>\n        /// <returns>The transformed final accumulator value</returns>\n        public static TResult Reduce<TSource, TAccumulate, TResult>(\n            this TSource[] source,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func,\n            Func<TAccumulate, TResult> resultSelector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n            if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));\n\n            TAccumulate result = seed;\n            foreach (var v in source)\n            {\n                result = func(result, v);\n            }\n\n            return resultSelector(result);\n        }\n\n        // ------------------------------ this Spans --------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Applies an accumulator function over an array.\n        /// </summary>        \n        /// <param name=\"source\">An array to aggregate over.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <returns>The final accumulator value</returns>\n        public static TSource Reduce<TSource>(this Span<TSource> source, Func<TSource, TSource, TSource> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            TSource result = source[0];\n            for (int i = 1; i < source.Length; i++)\n            {\n                result = func(result, source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Applies an accumulator function over an array. The specified seed\n        /// value is used as the initial accumulator value.\n        /// </summary>        \n        /// <param name=\"source\">An array to aggregate over.</param>\n        /// <param name=\"seed\">The initial accumulator value.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <returns>The final accumulator value</returns>\n        public static TAccumulate Reduce<TSource, TAccumulate>(this Span<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            TAccumulate result = seed;\n            foreach (var v in source)\n            {\n                result = func(result, v);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Applies an accumulator function over an array. The specified seed\n        /// value is used as the initial accumulator value, and the specified \n        /// function is used to select the result value.\n        /// </summary>        \n        /// <param name=\"source\">An array to aggregate over.</param>\n        /// <param name=\"seed\">The initial accumulator value.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <param name=\"resultSelector\">A function to transform the final accumulator value into the result value.</param>\n        /// <returns>The transformed final accumulator value</returns>\n        public static TResult Reduce<TSource, TAccumulate, TResult>(\n            this Span<TSource> source,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func,\n            Func<TAccumulate, TResult> resultSelector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n            if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));\n\n            TAccumulate result = seed;\n            foreach (var v in source)\n            {\n                result = func(result, v);\n            }\n\n            return resultSelector(result);\n        }\n#endif\n\n        // ------------------------------ Lists --------------------------\n\n        /// <summary>\n        /// Applies an accumulator function over a List.\n        /// </summary>\n        /// <typeparam name=\"TSource\"></typeparam>\n        /// <param name=\"source\">A List to aggregate over.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <returns>The final accumulator value</returns>\n        public static TSource Reduce<TSource>(this List<TSource> source, Func<TSource, TSource, TSource> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            TSource result = source[0];\n            for (int i = 1; i < source.Count; i++)\n            {\n                result = func(result, source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Applies an accumulator function over a List. The specified seed\n        /// value is used as the initial accumulator value.\n        /// </summary>        \n        /// <param name=\"source\">A List to aggregate over.</param>\n        /// <param name=\"seed\">The initial accumulator value.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <returns>The final accumulator value</returns>\n        public static TAccumulate Reduce<TSource, TAccumulate>(this List<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            TAccumulate result = seed;\n            for (int i = 0; i < source.Count; i++)\n            {\n                result = func(result, source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Applies an accumulator function over a List. The specified seed\n        /// value is used as the initial accumulator value, and the specified \n        /// function is used to select the result value.\n        /// </summary>        \n        /// <param name=\"source\">A List to aggregate over.</param>\n        /// <param name=\"seed\">The initial accumulator value.</param>\n        /// <param name=\"func\">An accumulator function to be invoked on each element</param>\n        /// <param name=\"resultSelector\">A function to transform the final accumulator value into the result value.</param>\n        /// <returns>The transformed final accumulator value</returns>\n        public static TResult Reduce<TSource, TAccumulate, TResult>(\n            this List<TSource> source,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func,\n            Func<TAccumulate, TResult> resultSelector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (func == null) throw new ArgumentNullException(nameof(func));\n            if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));\n\n            TAccumulate result = seed;\n            for (int i = 0; i < source.Count; i++)\n            {\n                result = func(result, source[i]);\n            }\n\n            return resultSelector(result);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Aggregate.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7318fcfc949ae1e45a0fb682dc976e17\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/AnyAll.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS --------------------------------------------\n\n        /// <summary>\n        /// Determines whether an array contains any elements\n        /// </summary>        \n        /// <param name=\"source\">The array to check for emptiness</param>\n        /// <returns>true if the source array contains any elements, otherwise, false/</returns>\n        public static bool Any<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            return source.Length > 0;\n        }\n\n\n        /// <summary>\n        /// Determines whether any element of an array satisfies a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array whose elements to apply the predicate to.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>true if any elements in the source array pass the test in the specified predicate; otherwise, false.</returns>\n        public static bool Any<TSource>(this TSource[] source, Predicate<TSource> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            return Array.Exists(source, predicate);\n        }\n\n\n        /// <summary>\n        /// Determines whether all elements of an array satisfy a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array that contains the elements to apply the predicate to.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>true if every element of the source array passes the test in the specified\n        /// predicate, or if the array is empty; otherwise, false</returns>\n        public static bool AllF<TSource>(this TSource[] source, Predicate<TSource> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            return Array.TrueForAll(source, predicate);\n        }\n\n        // --------------------------  this SpanS --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Determines whether an array contains any elements\n        /// </summary>        \n        /// <param name=\"source\">The array to check for emptiness</param>\n        /// <returns>true if the source array contains any elements, otherwise, false/</returns>\n        public static bool Any<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            return source.Length > 0;\n        }\n\n\n        /// <summary>\n        /// Determines whether any element of an array satisfies a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array whose elements to apply the predicate to.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>true if any elements in the source array pass the test in the specified predicate; otherwise, false.</returns>\n        public static bool Any<TSource>(this Span<TSource> source, Predicate<TSource> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i])) return true;\n            }\n\n            return false;\n        }\n\n\n        /// <summary>\n        /// Determines whether all elements of an array satisfy a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array that contains the elements to apply the predicate to.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>true if every element of the source array passes the test in the specified\n        /// predicate, or if the array is empty; otherwise, false</returns>\n        public static bool AllF<TSource>(this Span<TSource> source, Predicate<TSource> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (!predicate(source[i])) return false;\n            }\n\n            return true;\n        }\n#endif\n\n\n        // --------------------------  Lists --------------------------------------------\n        /// <summary>\n        /// Determines whether a list contains any elements\n        /// </summary>        \n        /// <param name=\"source\">The list to check for emptiness</param>\n        /// <returns>true if the source list contains any elements, otherwise, false/</returns>\n        public static bool Any<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            return source.Count > 0;\n        }\n\n        /// <summary>\n        /// Determines whether any element of an array satisfies a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array whose elements to apply the predicate to.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>true if any elements in the source array pass the test in the specified predicate; otherwise, false.</returns>\n        public static bool Any<TSource>(this List<TSource> source, Predicate<TSource> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            return source.Exists(predicate);\n        }\n\n        /// <summary>\n        /// Determines whether all elements of a list satisfy a condition.\n        /// </summary>        \n        /// <param name=\"source\">A list that contains the elements to apply the predicate to.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>true if every element of the source array passes the test in the specified\n        /// predicate, or if the list is empty; otherwise, false</returns>\n        public static bool AllF<TSource>(this List<TSource> source, Predicate<TSource> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            return source.TrueForAll(predicate);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/AnyAll.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 79a5d5f5ebe679e439be08f9273ee22a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Average.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average(this int[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this T[] source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average(this long[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this T[] source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static float Average(this float[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += source[i];\n            }\n\n            return (float)(sum / source.Length);\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static float Average<T>(this T[] source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return (float)(sum / source.Length);\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average(this double[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this T[] source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static decimal Average(this decimal[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static decimal Average<T>(this T[] source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum / source.Length;\n        }\n\n        // --------------------------  this SpanS  --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average(this Span<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this Span<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average(this Span<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this Span<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Length; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return (double)sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static float Average(this Span<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += source[i];\n            }\n\n            return (float)(sum / source.Length);\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static float Average<T>(this Span<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return (float)(sum / source.Length);\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average(this Span<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this Span<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of an array\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the average of.</param>\n        /// <returns>The average of the array.</returns>\n        public static decimal Average(this Span<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum / source.Length;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static decimal Average<T>(this Span<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum / source.Length;\n        }\n#endif\n\n        // --------------------------  Lists  --------------------------------------------\n\n        /// <summary>\n        /// Computes the average of a list.\n        /// </summary>\n        /// <param name=\"source\">The list to calculate the average of.</param>\n        /// <returns>The average of the list.</returns>\n        public static double Average(this List<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return (double)sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this List<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return (double)sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of a list.\n        /// </summary>\n        /// <param name=\"source\">The list to calculate the average of.</param>\n        /// <returns>The average of the list.</returns>\n        public static double Average(this List<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return (double)sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this List<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return (double)sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of a list.\n        /// </summary>\n        /// <param name=\"source\">The list to calculate the average of.</param>\n        /// <returns>The average of the list.</returns>\n        public static float Average(this List<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += source[i];\n            }\n\n            return (float)(sum / source.Count);\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static float Average<T>(this List<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return (float)(sum / source.Count);\n        }\n\n        /// <summary>\n        /// Computes the average of a list.\n        /// </summary>\n        /// <param name=\"source\">The list to calculate the average of.</param>\n        /// <returns>The average of the list.</returns>\n        public static double Average(this List<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static double Average<T>(this List<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of a list.\n        /// </summary>\n        /// <param name=\"source\">The list to calculate the average of.</param>\n        /// <returns>The average of the list.</returns>\n        public static decimal Average(this List<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum / source.Count;\n        }\n\n        /// <summary>\n        /// Computes the average of values obtained by invoking a transform function on\n        /// each element of the input array.\n        /// </summary>\n        /// <param name=\"source\">The array to calculate the transformed average of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The average of the array.</returns>\n        public static decimal Average<T>(this List<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum / source.Count;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Average.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c05cbaf5747bb654fb7fbad5a184abfe\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Chunk.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        /// Splits the given sequence into chunks of the given size.\n        /// If the sequence length isn't evenly divisible by the chunk size,\n        /// the last chunk will contain all remaining elements.\n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <param name=\"chunkSize\"></param>\n        /// <typeparam name=\"TSource\"></typeparam>\n        /// <returns></returns>\n        public static TSource[][] Chunk<TSource>(this TSource[] source, int chunkSize)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize));\n\n            int size = source.Length / chunkSize;\n            int extraSize = source.Length % chunkSize;\n            if (extraSize != 0) size++;\n            var result = new TSource[size][];\n            int currentIndex = 0;\n            int indexChunk = 0;\n            if (size != 0)\n            {\n                foreach (var element in source)\n                {\n                    if (result[indexChunk] == null)\n                    {\n                        if (extraSize != 0 && indexChunk == size - 1)\n                        {\n                            result[indexChunk] = new TSource[extraSize];\n                        }\n                        else\n                        {\n                            result[indexChunk] = new TSource[chunkSize];\n                        }\n                    }\n\n                    result[indexChunk][currentIndex++] = element;\n\n                    if (currentIndex == chunkSize)\n                    {\n                        indexChunk++;\n                        currentIndex = 0;\n                    }\n                }\n            }\n\n            return result;\n        }\n\n\n        // --------------------------  LISTS  --------------------------------------------\n\n        /// <summary>\n        /// Splits the given sequence into chunks of the given size.\n        /// If the sequence length isn't evenly divisible by the chunk size,\n        /// the last chunk will contain all remaining elements.\n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <param name=\"chunkSize\"></param>\n        /// <typeparam name=\"TSource\"></typeparam>\n        /// <returns></returns>\n        public static List<List<TSource>> Chunk<TSource>(this List<TSource> source, int chunkSize)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize));\n\n            int size = source.Count / chunkSize;\n            int extraSize = source.Count % chunkSize;\n            if (extraSize != 0) size++;\n            var result = new List<List<TSource>>(size);\n            var currentIndex = 0;\n            var indexChunk = 0;\n            if (size != 0)\n            {\n                for (int i = 0; i < size; i++)\n                {\n                    result.Add(new List<TSource>());\n                }\n\n                foreach (var element in source)\n                {\n                    result[indexChunk] = result[indexChunk] ?? new List<TSource>();\n                    result[indexChunk].Add(element);\n                    currentIndex++;\n\n                    if (currentIndex == chunkSize)\n                    {\n                        indexChunk++;\n                        currentIndex = 0;\n                    }\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Splits the given sequence into chunks of the given size.\n        /// If the sequence length isn't evenly divisible by the chunk size,\n        /// the last chunk will contain all remaining elements.\n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <param name=\"chunkSize\"></param>\n        /// <typeparam name=\"TSource\"></typeparam>\n        /// <returns></returns>\n        public static TSource[][] ChunkToArray<TSource>(this List<TSource> source, int chunkSize)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (chunkSize <= 0) throw new ArgumentOutOfRangeException(nameof(chunkSize));\n\n            int size = source.Count / chunkSize;\n            int extraSize = source.Count % chunkSize;\n            if (extraSize != 0) size++;\n            var result = new TSource[size][];\n            int currentIndex = 0;\n            int indexChunk = 0;\n            if (size != 0)\n            {\n                foreach (var element in source)\n                {\n                    if (result[indexChunk] == null)\n                    {\n                        if (extraSize != 0 && indexChunk == size - 1)\n                        {\n                            result[indexChunk] = new TSource[extraSize];\n                        }\n                        else\n                        {\n                            result[indexChunk] = new TSource[chunkSize];\n                        }\n                    }\n\n                    result[indexChunk][currentIndex++] = element;\n\n                    if (currentIndex == chunkSize)\n                    {\n                        indexChunk++;\n                        currentIndex = 0;\n                    }\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Chunk.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e508a8542516477caaedb478e17e9c08\ntimeCreated: 1664520886"
  },
  {
    "path": "VirtueSky/Linq/Contains.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        /// Determines whether an array contains a specified element by using the \n        /// provided IEqualityComparer.\n        /// </summary>        \n        /// <param name=\"source\">An array in which to locate a value.</param>\n        /// <param name=\"value\">The value to locate.</param>\n        /// <param name=\"comparer\">An equality comparer to compare values.</param>\n        /// <returns>true if the source sequence contains an element that has the specified value; otherwise, false.</returns>\n        public static bool Contains<TSource>(this TSource[] source, TSource value, IEqualityComparer<TSource> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (comparer == null) return Array.IndexOf(source, value) != -1;\n\n            foreach (TSource e in source)\n            {\n                if (comparer.Equals(e, value))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        // --------------------------  this SpanS  --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Determines whether an array contains a specified element by using the \n        /// provided IEqualityComparer.\n        /// </summary>        \n        /// <param name=\"source\">An array in which to locate a value.</param>\n        /// <param name=\"value\">The value to locate.</param>\n        /// <param name=\"comparer\">An equality comparer to compare values.</param>\n        /// <returns>true if the source sequence contains an element that has the specified value; otherwise, false.</returns>\n        public static bool Contains<TSource>(this Span<TSource> source, TSource value, IEqualityComparer<TSource> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (comparer == null) comparer = EqualityComparer<TSource>.Default;\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (comparer.Equals(source[i], value))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n#endif\n\n\n        // --------------------------  Lists --------------------------------------------\n\n        /// <summary>\n        /// Determines whether a list contains a specified element by using the \n        /// provided IEqualityComparer.\n        /// </summary>        \n        /// <param name=\"source\">A list in which to locate a value.</param>\n        /// <param name=\"value\">The value to locate.</param>\n        /// <param name=\"comparer\">An equality comparer to compare values.</param>\n        /// <returns>true if the source sequence contains an element that has the specified value; otherwise, false.</returns>\n        public static bool Contains<TSource>(this List<TSource> source, TSource value, IEqualityComparer<TSource> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (comparer == null) return source.IndexOf(value) != -1;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (comparer.Equals(source[i], value))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Contains.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 24b2f9dba1b94ef45a66fa604d7154a5\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Count.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  Arrays --------------------------------------------\n\n        /// <summary>\n        /// Returns a number that represents how many elements in the specified\n        /// array satisfy a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array that contains elements to be tested and counted.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A number that represents how many elements in the array satisfy the condition\n        /// in the predicate function.</returns>\n        public static int Count<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                checked\n                {\n                    if (predicate(source[i]))\n                    {\n                        count++;\n                    }\n                }\n            }\n\n            return count;\n        }\n\n        // --------------------------  this Spans --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns a number that represents how many elements in the specified\n        /// array satisfy a condition.\n        /// </summary>        \n        /// <param name=\"source\">An array that contains elements to be tested and counted.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A number that represents how many elements in the array satisfy the condition\n        /// in the predicate function.</returns>\n        public static int Count<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                checked\n                {\n                    if (predicate(source[i]))\n                    {\n                        count++;\n                    }\n                }\n            }\n\n            return count;\n        }\n#endif\n\n\n        // ------------------------------ Lists ---------------------\n\n        /// <summary>\n        /// Returns a number that represents how many elements in the specified\n        /// list satisfy a condition.\n        /// </summary>        \n        /// <param name=\"source\">A list that contains elements to be tested and counted.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A number that represents how many elements in the list satisfy the condition\n        /// in the predicate function.</returns>\n        public static int Count<T>(this List<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                checked\n                {\n                    if (predicate(source[i]))\n                    {\n                        count++;\n                    }\n                }\n            }\n\n            return count;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Count.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3aaa52a419914b34eb3def88aab913e0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Distinct.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source)\n        {\n            return System.Linq.Enumerable.Distinct(source);\n        }\n\n        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)\n        {\n            return System.Linq.Enumerable.Distinct(source, comparer);\n        }\n\n        public static System.Linq.ParallelQuery<TSource> Distinct<TSource>(this System.Linq.ParallelQuery<TSource> source)\n        {\n            return System.Linq.ParallelEnumerable.Distinct(source);\n        }\n\n        public static System.Linq.ParallelQuery<TSource> Distinct<TSource>(this System.Linq.ParallelQuery<TSource> source, IEqualityComparer<TSource> comparer)\n        {\n            return System.Linq.ParallelEnumerable.Distinct(source, comparer);\n        }\n\n        /// <summary>\n        /// Returns distinct elements from the given sequence using the default equality comparer\n        /// to compare values projected by <paramref name=\"projection\"/>.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements of <paramref name=\"source\"/>.</typeparam>\n        /// <typeparam name=\"TResult\">The type of the projected value for each element of the sequence.</typeparam>\n        /// <param name=\"source\">The sequence.</param>\n        /// <param name=\"projection\">The projection that is applied to each element to retrieve the value which is being compared.</param>\n        /// <returns>A sequence of elements whose projected values are distinct.</returns>\n        public static IEnumerable<TSource> Distinct<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> projection)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (projection == null) throw new ArgumentNullException(nameof(projection));\n\n            return DistinctIterator(source, projection, EqualityComparer<TResult>.Default);\n        }\n\n        /// <summary>\n        /// Returns distinct elements from the given sequence using the specified equality comparer\n        /// to compare values projected by <paramref name=\"projection\"/>.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements of <paramref name=\"source\"/>.</typeparam>\n        /// <typeparam name=\"TResult\">The type of the projected value for each element of the sequence.</typeparam>\n        /// <param name=\"source\">The sequence.</param>\n        /// <param name=\"projection\">The projection that is applied to each element to retrieve the value which is being compared.</param>\n        /// <param name=\"equalityComparer\">The equality comparer to use for comparing the projected values.</param>\n        /// <returns>A sequence of elements whose projected values are considered distinct by the specified equality comparer.</returns>\n        public static IEnumerable<TSource> Distinct<TSource, TResult>(\n            this IEnumerable<TSource> source,\n            Func<TSource, TResult> projection,\n            IEqualityComparer<TResult> equalityComparer)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n            if (projection == null) throw new ArgumentNullException(nameof(projection));\n            if (equalityComparer == null) throw new ArgumentNullException(nameof(equalityComparer));\n\n            return DistinctIterator(source, projection, equalityComparer);\n        }\n\n        private static IEnumerable<TSource> DistinctIterator<TSource, TResult>(\n            IEnumerable<TSource> source,\n            Func<TSource, TResult> projection,\n            IEqualityComparer<TResult> equalityComparer)\n        {\n            var alreadySeenValues = new HashSet<TResult>(equalityComparer);\n\n            foreach (var element in source)\n            {\n                var value = projection(element);\n\n                if (alreadySeenValues.Contains(value))\n                {\n                    continue;\n                }\n\n                yield return element;\n                alreadySeenValues.Add(value);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Distinct.cs.meta",
    "content": "fileFormatVersion: 2\nguid: df53bfa4cfe4fda4fa8a6ccd414efa0a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/First.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  Arrays --------------------------------------------\n\n        /// <summary>\n        /// Returns the first element of an array.\n        /// </summary>        \n        /// <param name=\"source\">The array to return the first element of.</param>\n        /// <returns>The first element in the specified array.</returns>\n        public static T First<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the first element in an array that satisfies a specified condition.\n        /// </summary>        \n        /// <param name=\"source\">An array to return an element from.</param>\n        /// <param name=\"predicate\">A function to teast each element for a condition.</param>\n        /// <returns>The first element that satisfies the condition.</returns>\n        public static T First<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    return source[i];\n                }\n            }\n\n            throw new InvalidOperationException(\"Sequence contains no matching element\");\n        }\n\n\n        /// <summary>\n        /// Returns the first element of an array, or a default value if the\n        /// array contains no elements.\n        /// </summary>             \n        /// <param name=\"source\">The array to return the first element of.</param>\n        /// <returns>default value if source is empty, otherwise, the first element\n        /// in source.</returns>        \n        public static T FirstOrDefault<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) return default;\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the first element of the sequence that satisfies a condition or a \n        /// default value if no such element is found.\n        /// </summary>        \n        /// <param name=\"source\">An IEnumerable to return an element from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns></returns>\n        public static T FirstOrDefault<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    return source[i];\n                }\n            }\n\n            return default;\n        }\n        // --------------------------  this Span --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns the first element of an array.\n        /// </summary>        \n        /// <param name=\"source\">The array to return the first element of.</param>\n        /// <returns>The first element in the specified array.</returns>\n        public static T First<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the first element in an array that satisfies a specified condition.\n        /// </summary>        \n        /// <param name=\"source\">An array to return an element from.</param>\n        /// <param name=\"predicate\">A function to teast each element for a condition.</param>\n        /// <returns>The first element that satisfies the condition.</returns>\n        public static T First<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    return source[i];\n                }\n            }\n\n            throw new InvalidOperationException(\"Sequence contains no matching element\");\n        }\n\n\n        /// <summary>\n        /// Returns the first element of an array, or a default value if the\n        /// array contains no elements.\n        /// </summary>             \n        /// <param name=\"source\">The array to return the first element of.</param>\n        /// <returns>default value if source is empty, otherwise, the first element\n        /// in source.</returns>        \n        public static T FirstOrDefault<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) return default;\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the first element of the sequence that satisfies a condition or a \n        /// default value if no such element is found.\n        /// </summary>        \n        /// <param name=\"source\">An IEnumerable to return an element from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns></returns>\n        public static T FirstOrDefault<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    return source[i];\n                }\n            }\n\n            return default;\n        }\n#endif\n\n        // --------------------------  Lists --------------------------------------------\n\n        /// <summary>\n        /// Returns the first element of a list\n        /// </summary>        \n        /// <param name=\"source\">The list to return the first element of.</param>\n        /// <returns>The first element in the specified list.</returns>   \n        public static T First<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the first element in a list that satisfies a specified condition.\n        /// </summary>        \n        /// <param name=\"source\">An list to return an element from.</param>\n        /// <param name=\"predicate\">A function to teast each element for a condition.</param>\n        /// <returns>The first element in the list that satisfies the condition.</returns>       \n        public static T First<T>(this List<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var firstIndex = source.FindIndex(predicate);\n            if (firstIndex == -1) throw new InvalidOperationException(\"Sequence contains no matching element\");\n            return source[firstIndex];\n        }\n\n        /// <summary>\n        /// Returns the first element of an array, or a default value if the\n        /// array contains no elements.\n        /// </summary>             \n        /// <param name=\"source\">The array to return the first element of.</param>\n        /// <returns>default value if source is empty, otherwise, the first element\n        /// in source.</returns>      \n        public static T FirstOrDefault<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) return default;\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the first element of the sequence that satisfies a condition or a \n        /// default value if no such element is found.\n        /// </summary>        \n        /// <param name=\"source\">An IEnumerable to return an element from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns></returns>\n        public static T FirstOrDefault<T>(this List<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var firstIndex = source.FindIndex(predicate);\n            if (firstIndex == -1) return default;\n            return source[firstIndex];\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/First.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8c1d92ed50ac2284d8e1dbeddda1f1d1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Flatten.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n        /// <summary>\n        /// Returns a flattened sequence that contains the concatenation of all the nested sequences' elements.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements of <paramref name=\"source\"/>.</typeparam>\n        /// <param name=\"source\">A sequence of sequences to be flattened.</param>\n        /// <returns>The concatenation of all the nested sequences' elements.</returns>\n        public static TSource[] Flatten<TSource>(this TSource[][] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            var result = new List<TSource>();\n\n            foreach (var array in source)\n            {\n                foreach (var s1 in array)\n                {\n                    result.Add(s1);\n                }\n            }\n\n            return result.ToArray();\n        }\n\n\n        // --------------------------  LISTS  --------------------------------------------\n\n        // --------------------------  ARRAYS  --------------------------------------------\n        /// <summary>\n        /// Returns a flattened sequence that contains the concatenation of all the nested sequences' elements.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements of <paramref name=\"source\"/>.</typeparam>\n        /// <param name=\"source\">A sequence of sequences to be flattened.</param>\n        /// <returns>The concatenation of all the nested sequences' elements.</returns>\n        public static List<TSource> Flatten<TSource>(this List<List<TSource>> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            var result = new List<TSource>();\n\n            foreach (var array in source)\n            {\n                for (var i = 0; i < array.Count; i++)\n                {\n                    result.Add(array[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns a flattened sequence that contains the concatenation of all the nested sequences' elements.\n        /// </summary>\n        /// <typeparam name=\"TSource\">The type of the elements of <paramref name=\"source\"/>.</typeparam>\n        /// <param name=\"source\">A sequence of sequences to be flattened.</param>\n        /// <returns>The concatenation of all the nested sequences' elements.</returns>\n        public static List<TSource> Flatten<TSource>(this List<TSource[]> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            var result = new List<TSource>();\n\n            foreach (var array in source)\n            {\n                foreach (var s1 in array)\n                {\n                    result.Add(s1);\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Flatten.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e893bfd4dd584645830be4eff1d00e33\ntimeCreated: 1664529405"
  },
  {
    "path": "VirtueSky/Linq/Last.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  Arrays --------------------------------------------\n\n        /// <summary>\n        /// Returns the last element of a sequence.\n        /// </summary>        \n        /// <param name=\"source\">An sequence to return the last element of.</param>\n        /// <returns>The value at the last position in the source sequence.</returns>\n        public static T Last<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            return source[source.Length - 1];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence that satisfies a specified condition.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return an element from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns></returns>       \n        public static T Last<T>(this T[] source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var lastIndex = Array.FindLastIndex(source, predicate);\n\n            if (lastIndex == -1) throw new InvalidOperationException(\"Sequence contains no matching element\");\n            return source[lastIndex];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence, or a default value if the sequence contains no elements.\n        /// </summary>        \n        /// <param name=\"source\">An sequence to return the last element of.</param>\n        /// <returns>default value if the source sequence is empty; otherwise, \n        /// the last element in the sequence</returns>\n        public static T LastOrDefault<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0)\n            {\n                return default;\n            }\n\n            return source[source.Length - 1];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the last element of.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>default value if the sequence is empty or if no elements pass the test \n        /// in the predicate function; otherwise, the last element that passes the test in the \n        /// predicate function.</returns>\n        public static T LastOrDefault<T>(this T[] source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var lastIndex = Array.FindLastIndex(source, predicate);\n\n            if (lastIndex == -1) return default;\n            return source[lastIndex];\n        }\n\n        // --------------------------  this Spans --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns the last element of a sequence.\n        /// </summary>        \n        /// <param name=\"source\">An sequence to return the last element of.</param>\n        /// <returns>The value at the last position in the source sequence.</returns>\n        public static T Last<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            return source[source.Length - 1];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence that satisfies a specified condition.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return an element from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns></returns>       \n        public static T Last<T>(this Span<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = source.Length - 1; i >= 0; i--)\n            {\n                if (predicate(source[i])) return source[i];\n            }\n\n            throw new InvalidOperationException(\"Sequence contains no matching element\");\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence, or a default value if the sequence contains no elements.\n        /// </summary>        \n        /// <param name=\"source\">An sequence to return the last element of.</param>\n        /// <returns>default value if the source sequence is empty; otherwise, \n        /// the last element in the sequence</returns>\n        public static T LastOrDefault<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0)\n            {\n                return default;\n            }\n\n            return source[source.Length - 1];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the last element of.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>default value if the sequence is empty or if no elements pass the test \n        /// in the predicate function; otherwise, the last element that passes the test in the \n        /// predicate function.</returns>\n        public static T LastOrDefault<T>(this Span<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            for (int i = source.Length - 1; i >= 0; i--)\n            {\n                if (predicate(source[i])) return source[i];\n            }\n\n\n            return default;\n        }\n#endif\n\n        // --------------------------  Lists --------------------------------------------\n\n        /// <summary>\n        /// Returns the last element of a sequence.\n        /// </summary>        \n        /// <param name=\"source\">An sequence to return the last element of.</param>\n        /// <returns>The value at the last position in the source sequence.</returns>\n        public static T Last<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            return source[source.Count - 1];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence that satisfies a specified condition.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return an element from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns></returns>\n        public static T Last<T>(this List<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var lastIndex = source.FindLastIndex(predicate);\n\n            if (lastIndex == -1) throw new InvalidOperationException(\"Sequence contains no matching element\");\n            return source[lastIndex];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence, or a default value if the sequence contains no elements.\n        /// </summary>        \n        /// <param name=\"source\">An sequence to return the last element of.</param>\n        /// <returns>default value if the source sequence is empty; otherwise, \n        /// the last element in the sequence</returns>        \n        public static T LastOrDefault<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0)\n            {\n                return default;\n            }\n\n            return source[source.Count - 1];\n        }\n\n        /// <summary>\n        /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the last element of.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>default value if the sequence is empty or if no elements pass the test \n        /// in the predicate function; otherwise, the last element that passes the test in the \n        /// predicate function.</returns>\n        public static T LastOrDefault<T>(this List<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var lastIndex = source.FindLastIndex(predicate);\n\n            if (lastIndex == -1) return default;\n            return source[lastIndex];\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Last.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6bc600c7bc78bb244bf70dc75dd15fb8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Max.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    //int, long, float,double, decimal\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static T Max<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<T> comparer = Comparer<T>.Default;\n            T r = default(T);\n            if (r == null)\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (source[i] != null && comparer.Compare(source[i], r) > 0) r = source[i];\n                }\n            }\n            else\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (comparer.Compare(source[i], r) > 0) r = source[i];\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static TResult Max<T, TResult>(this T[] source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<TResult> comparer = Comparer<TResult>.Default;\n            TResult r = default(TResult);\n            if (r == null)\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (v != null && comparer.Compare(v, r) > 0) r = v;\n                }\n            }\n            else\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (comparer.Compare(v, r) > 0) r = v;\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static int Max(this int[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            int r = int.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static int Max<T>(this T[] source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int r = int.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static long Max(this long[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long r = long.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static long Max<T>(this T[] source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long r = long.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static float Max(this float[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            float r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                if (!float.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static float Max<T>(this T[] source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            float r = selector(source[0]);\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                var v = selector(source[startIndex]);\n                if (!float.IsNaN(v))\n                {\n                    r = v;\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static double Max(this double[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                if (!double.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static double Max<T>(this T[] source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double r = selector(source[0]);\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                var v = selector(source[startIndex]);\n                if (!double.IsNaN(v))\n                {\n                    r = v;\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static decimal Max(this decimal[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static decimal Max<T>(this T[] source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal r = decimal.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        // --------------------------  this Spans  --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static T Max<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<T> comparer = Comparer<T>.Default;\n            T r = default(T);\n            if (r == null)\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (source[i] != null && comparer.Compare(source[i], r) > 0) r = source[i];\n                }\n            }\n            else\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (comparer.Compare(source[i], r) > 0) r = source[i];\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static TResult Max<T, TResult>(this Span<T> source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<TResult> comparer = Comparer<TResult>.Default;\n            TResult r = default(TResult);\n            if (r == null)\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (v != null && comparer.Compare(v, r) > 0) r = v;\n                }\n            }\n            else\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (comparer.Compare(v, r) > 0) r = v;\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static int Max(this Span<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            int r = int.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static int Max<T>(this Span<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int r = int.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static long Max(this Span<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long r = long.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static long Max<T>(this Span<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long r = long.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static float Max(this Span<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            float r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                if (!float.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static float Max<T>(this Span<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            float r = selector(source[0]);\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                var v = selector(source[startIndex]);\n                if (!float.IsNaN(v))\n                {\n                    r = v;\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static double Max(this Span<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                if (!double.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static double Max<T>(this Span<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double r = selector(source[0]);\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                var v = selector(source[startIndex]);\n                if (!double.IsNaN(v))\n                {\n                    r = v;\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static decimal Max(this Span<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static decimal Max<T>(this Span<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal r = decimal.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n#endif\n\n        // --------------------------  LISTS  --------------------------------------------\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static T Max<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<T> comparer = Comparer<T>.Default;\n            T r = default(T);\n            if (r == null)\n            {\n                r = source[0];\n                for (int i = 1; i < source.Count; i++)\n                {\n                    if (source[i] != null && comparer.Compare(source[i], r) > 0) r = source[i];\n                }\n            }\n            else\n            {\n                r = source[0];\n                for (int i = 1; i < source.Count; i++)\n                {\n                    if (comparer.Compare(source[i], r) > 0) r = source[i];\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static TResult Max<T, TResult>(this List<T> source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<TResult> comparer = Comparer<TResult>.Default;\n            TResult r = default(TResult);\n            if (r == null)\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Count; i++)\n                {\n                    var v = selector(source[i]);\n                    if (v != null && comparer.Compare(v, r) > 0) r = v;\n                }\n            }\n            else\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Count; i++)\n                {\n                    var v = selector(source[i]);\n                    if (comparer.Compare(v, r) > 0) r = v;\n                }\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static int Max(this List<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            int r = int.MinValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static int Max<T>(this List<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int r = int.MinValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static long Max(this List<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long r = long.MinValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static long Max<T>(this List<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long r = long.MinValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static float Max(this List<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            float r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Count; startIndex++)\n            {\n                if (!float.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Count; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static float Max<T>(this List<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            float r = selector(source[0]);\n            int startIndex = 0;\n            for (; startIndex < source.Count; startIndex++)\n            {\n                var v = selector(source[startIndex]);\n                if (!float.IsNaN(v))\n                {\n                    r = v;\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static double Max(this List<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Count; startIndex++)\n            {\n                if (!double.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Count; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static double Max<T>(this List<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double r = selector(source[0]);\n            int startIndex = 0;\n            for (; startIndex < source.Count; startIndex++)\n            {\n                var v = selector(source[startIndex]);\n                if (!double.IsNaN(v))\n                {\n                    r = v;\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the maximum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum of.</param>\n        /// <returns>The maximum value in the sequence</returns>\n        public static decimal Max(this List<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MinValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static decimal Max<T>(this List<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MinValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v > r) r = v;\n            }\n\n            return r;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Max.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5a7be0bf1dc94a745a794b9c63d53b42\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Min.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    //int, long, float,double, decimal\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static T Min<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<T> comparer = Comparer<T>.Default;\n            T r = default(T);\n            if (r == null)\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (source[i] != null && comparer.Compare(source[i], r) < 0) r = source[i];\n                }\n            }\n            else\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (comparer.Compare(source[i], r) < 0) r = source[i];\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static TResult Min<T, TResult>(this T[] source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<TResult> comparer = Comparer<TResult>.Default;\n            TResult r = default(TResult);\n            if (r == null)\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (v != null && comparer.Compare(v, r) < 0) r = v;\n                }\n            }\n            else\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (comparer.Compare(v, r) < 0) r = v;\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static int Min(this int[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static int Min<T>(this T[] source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static long Min(this long[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long r = long.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static long Min<T>(this T[] source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long r = long.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static float Min(this float[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (float.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static float Min<T>(this T[] source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n                else if (float.IsNaN(v)) return v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static double Min(this double[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double r = double.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (double.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static double Min<T>(this T[] source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double r = double.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n                else if (double.IsNaN(v)) return v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static decimal Min(this decimal[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static decimal Min<T>(this T[] source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal r = decimal.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n        // --------------------------  this Spans  --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static T Min<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<T> comparer = Comparer<T>.Default;\n            T r = default(T);\n            if (r == null)\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (source[i] != null && comparer.Compare(source[i], r) < 0) r = source[i];\n                }\n            }\n            else\n            {\n                r = source[0];\n                for (int i = 1; i < source.Length; i++)\n                {\n                    if (comparer.Compare(source[i], r) < 0) r = source[i];\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static TResult Min<T, TResult>(this Span<T> source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<TResult> comparer = Comparer<TResult>.Default;\n            TResult r = default(TResult);\n            if (r == null)\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (v != null && comparer.Compare(v, r) < 0) r = v;\n                }\n            }\n            else\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Length; i++)\n                {\n                    var v = selector(source[i]);\n                    if (comparer.Compare(v, r) < 0) r = v;\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static int Min(this Span<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static int Min<T>(this Span<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static long Min(this Span<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long r = long.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static long Min<T>(this Span<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long r = long.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static float Min(this Span<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (float.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static float Min<T>(this Span<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n                else if (float.IsNaN(v)) return v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static double Min(this Span<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double r = double.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (double.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static double Min<T>(this Span<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double r = double.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n                else if (double.IsNaN(v)) return v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static decimal Min(this Span<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static decimal Min<T>(this Span<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal r = decimal.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n#endif\n\n        // --------------------------  LISTS  --------------------------------------------\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static T Min<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<T> comparer = Comparer<T>.Default;\n            T r = default(T);\n            if (r == null)\n            {\n                r = source[0];\n                for (int i = 1; i < source.Count; i++)\n                {\n                    if (source[i] != null && comparer.Compare(source[i], r) < 0) r = source[i];\n                }\n            }\n            else\n            {\n                r = source[0];\n                for (int i = 1; i < source.Count; i++)\n                {\n                    if (comparer.Compare(source[i], r) < 0) r = source[i];\n                }\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static int Min(this List<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static int Min<T>(this List<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static long Min(this List<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            long r = long.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static long Min<T>(this List<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long r = long.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static float Min(this List<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (float.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static float Min<T>(this List<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n                else if (float.IsNaN(v)) return v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static double Min(this List<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            double r = double.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (double.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static double Min<T>(this List<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double r = double.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n                else if (double.IsNaN(v)) return v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Returns the minimum value in a sequence of values.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the minimum of.</param>\n        /// <returns>The minimum value in the sequence</returns>\n        public static decimal Min(this List<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static decimal Min<T>(this List<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            decimal r = decimal.MaxValue;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = selector(source[i]);\n                if (v < r) r = v;\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Invokes a transform function on each element of a sequence and returns the maximum value.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to determine the maximum value of.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>The maximum value in the transform of the sequence.</returns>\n        public static TResult Min<T, TResult>(this List<T> source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            Comparer<TResult> comparer = Comparer<TResult>.Default;\n            TResult r = default(TResult);\n            if (r == null)\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Count; i++)\n                {\n                    var v = selector(source[i]);\n                    if (v != null && comparer.Compare(v, r) < 0) r = v;\n                }\n            }\n            else\n            {\n                r = selector(source[0]);\n                for (int i = 1; i < source.Count; i++)\n                {\n                    var v = selector(source[i]);\n                    if (comparer.Compare(v, r) < 0) r = v;\n                }\n            }\n\n            return r;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Min.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c7ae4d8470b60b043b25b615582f6a0e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/OrderBy.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Sorts the elements of a sequence in ascending order according to a key.\n        /// Unlike standard Linq NOT a stable sort.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to order.</param>\n        /// <param name=\"keySelector\">A function to extract a key from an element.</param>\n        /// <param name=\"comparer\">A Comparer to compare keys.</param>\n        /// <returns>A sequence whose elements are ordered according to a key</returns>\n        public static TSource[] OrderBy<TSource, TKey>(this TSource[] source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));\n\n            if (comparer == null)\n            {\n                comparer = Comparer<TKey>.Default;\n            }\n\n            var keys = new TKey[source.Length];\n            for (int i = 0; i < keys.Length; i++)\n            {\n                keys[i] = keySelector(source[i]);\n            }\n\n            var result = (TSource[])source.Clone();\n            Array.Sort(keys, result, comparer);\n            return result;\n        }\n\n        /// <summary>\n        /// Sorts the elements of a sequence in descending order according to a key.\n        /// Unlike standard Linq NOT a stable sort.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to order.</param>\n        /// <param name=\"keySelector\">A function to extract a key from an element.</param>\n        /// <param name=\"comparer\">A Comparer to compare keys.</param>\n        /// <returns>A sequence whose elements are ordered according to a key</returns>\n        public static TSource[] OrderByDescending<TSource, TKey>(this TSource[] source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));\n\n            if (comparer == null)\n            {\n                comparer = Comparer<TKey>.Default;\n            }\n\n            var keys = new TKey[source.Length];\n            for (int i = 0; i < keys.Length; i++)\n            {\n                keys[i] = keySelector(source[i]);\n            }\n\n            var result = (TSource[])source.Clone();\n            Array.Sort(keys, result, comparer.Reverse());\n            return result;\n        }\n\n\n        // ---------------------- Lists\n\n        /// <summary>\n        /// Sorts the elements of a sequence in ascending order according to a key.\n        /// Unlike standard Linq NOT a stable sort.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to order.</param>\n        /// <param name=\"keySelector\">A function to extract a key from an element.</param>\n        /// <param name=\"comparer\">A Comparer to compare keys.</param>\n        /// <returns>A sequence whose elements are ordered according to a key</returns>\n        public static List<TSource> OrderBy<TSource, TKey>(this List<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));\n\n            if (comparer == null)\n            {\n                comparer = Comparer<TKey>.Default;\n            }\n\n            var result = new List<TSource>(source);\n            var lambdaComparer = new LambdaComparer<TSource, TKey>(keySelector, comparer);\n            result.Sort(lambdaComparer);\n            return result;\n        }\n\n        /// <summary>\n        /// Sorts the elements of a sequence in descending order according to a key.\n        /// Unlike standard Linq NOT a stable sort.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to order.</param>\n        /// <param name=\"keySelector\">A function to extract a key from an element.</param>\n        /// <param name=\"comparer\">A Comparer to compare keys.</param>\n        /// <returns>A sequence whose elements are ordered according to a key</returns>\n        public static List<TSource> OrderByDescending<TSource, TKey>(this List<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer = null)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));\n\n            if (comparer == null)\n            {\n                comparer = Comparer<TKey>.Default;\n            }\n\n            var result = new List<TSource>(source);\n            var lambdaComparer = new ReverseLambdaComparer<TSource, TKey>(keySelector, comparer);\n            result.Sort(lambdaComparer);\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/OrderBy.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4715c0497778f254dbfdae272dbf5648\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Range.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Generates a sequence of integral numbers within a specified range.\n        /// </summary>\n        /// <param name=\"start\">The value of the first integer in the sequence.</param>\n        /// <param name=\"count\">The number of sequential integers to generate.</param>\n        /// <returns>A sequence that contains a range of sequential integral numbers.</returns>\n        public static int[] RangeArray(int start, int count)\n        {\n            long max = ((long)start) + count - 1;\n            if (count < 0 || max > int.MaxValue) throw new ArgumentOutOfRangeException(nameof(count));\n\n            int[] result = new int[count];\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = i + start;\n            }\n\n            return result;\n        }\n\n\n        /// <summary>\n        /// Generates a sequence of integral numbers within a specified range.\n        /// </summary>\n        /// <param name=\"start\">The value of the first integer in the sequence.</param>\n        /// <param name=\"count\">The number of sequential integers to generate.</param>\n        /// <returns>A sequence that contains a range of sequential integral numbers.</returns>\n        public static List<int> RangeList(int start, int count)\n        {\n            long max = ((long)start) + count - 1;\n            if (count < 0 || max > int.MaxValue) throw new ArgumentOutOfRangeException(nameof(count));\n\n            var result = new List<int>(count);\n            for (int i = 0; i < count; i++)\n            {\n                result.Add(i + start);\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Range.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1b703cfc9555784ba8c8780bb7f13f2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Repeat.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // ------------------------ Arrays ---------------------------\n\n        /// <summary>\n        /// Generates a sequence that contains one repeated value.\n        /// </summary>        \n        /// <param name=\"element\">The value to be repeated.</param>\n        /// <param name=\"count\">The number of times to repeat the value in the generated sequence.</param>\n        /// <returns>A sequence that contains a repeated value</returns>\n        public static T[] RepeatArray<T>(T element, int count)\n        {\n            var result = new T[count];\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = element;\n            }\n\n            return result;\n        }\n\n        // ------------------------ Lists ---------------------------\n\n        /// <summary>\n        /// Generates a sequence that contains one repeated value.\n        /// </summary>        \n        /// <param name=\"element\">The value to be repeated.</param>\n        /// <param name=\"count\">The number of times to repeat the value in the generated sequence.</param>\n        /// <returns>A sequence that contains a repeated value</returns>\n        public static List<T> RepeatList<T>(T element, int count)\n        {\n            var result = new List<T>(count);\n            for (int i = 0; i < count; i++)\n            {\n                result.Add(element);\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Repeat.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 70b6f576d7a45084da893689dca2d9b0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Reverse.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Inverts the order of the elements in a sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to reverse.</param>\n        /// <returns>A sequence whose elements correspond to those of the input sequence in reverse order.</returns>\n        public static T[] Reverse<T>(this T[] source)\n        {\n            var result = new T[source.Length];\n            int lenLessOne = source.Length - 1;\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = source[lenLessOne - i];\n            }\n\n            return result;\n        }\n\n\n        /// <summary>\n        /// Inverts the order of the elements in a sequence in place.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to reverse.</param>        \n        public static void ReverseOrigin<T>(this T[] source)\n        {\n            Array.Reverse(source);\n        }\n\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Inverts the order of the elements in a sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to reverse.</param>\n        /// <returns>A sequence whose elements correspond to those of the input sequence in reverse order.</returns>\n        public static T[] Reverse<T>(this Span<T> source)\n        {\n            var result = new T[source.Length];\n            int lenLessOne = source.Length - 1;\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = source[lenLessOne - i];\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Inverts the order of the elements in a sequence in place.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to reverse.</param>        \n        public static void ReverseOrigin<T>(this Span<T> source)\n        {\n            MemoryExtensions.Reverse(source);\n        }\n#endif\n\n        /// <summary>\n        /// Inverts the order of the elements in a sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to reverse.</param>\n        /// <returns>A sequence whose elements correspond to those of the input sequence in reverse order.</returns>\n        public static List<T> Reverse<T>(this List<T> source)\n        {\n            var result = new List<T>(source.Count);\n            for (int i = source.Count - 1; i >= 0; i--)\n            {\n                result.Add(source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Inverts the order of the elements in a sequence in place.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to reverse.</param>        \n        public static void ReverseOrigin<T>(this List<T> source)\n        {\n            source.Reverse();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Reverse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 56aebe035b0b1994e9b763d9e3870335\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Select.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form in place.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on (map).</param>\n        /// <param name=\"selector\">A transform function to apply (map) to each element.</param>        \n        public static void MapOrigin<T>(this T[] source, Func<T, T> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                source[i] = selector(source[i]);\n            }\n        }\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form, in place, by incorporating the element's index.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on.</param>\n        /// <param name=\"selector\">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>        \n        public static void MapOrigin<T>(this T[] source, Func<T, int, T> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                source[i] = selector(source[i], i);\n            }\n        }\n\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form. (map in every other language)\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on (map).</param>\n        /// <param name=\"selector\">A transform function to apply (map) to each element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the transform function on each element (mapping) of source.</returns>\n        public static TResult[] Map<T, TResult>(this T[] source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new TResult[source.Length];\n            for (int i = 0; i < source.Length; i++)\n            {\n                r[i] = selector(source[i]);\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form by incorporating the element's index.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on.</param>\n        /// <param name=\"selector\">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the transform function on each element of source.</returns>\n        public static TResult[] Map<T, TResult>(this T[] source, Func<T, int, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new TResult[source.Length];\n            for (int i = 0; i < source.Length; i++)\n            {\n                r[i] = selector(source[i], i);\n            }\n\n            return r;\n        }\n\n        // --------------------------  this SpanS  --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Projects each element of a sequence into a new form in place.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on (map).</param>\n        /// <param name=\"selector\">A transform function to apply (map) to each element.</param>        \n        public static void MapOrigin<T>(this Span<T> source, Func<T, T> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                source[i] = selector(source[i]);\n            }\n        }\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form, in place, by incorporating the element's index.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on.</param>\n        /// <param name=\"selector\">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>        \n        public static void MapOrigin<T>(this Span<T> source, Func<T, int, T> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            for (int i = 0; i < source.Length; i++)\n            {\n                source[i] = selector(source[i], i);\n            }\n        }\n\n\n        /// <summary>\n        ///  Projects each element of a sequence into a new form. (map in every other language)\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on (map).</param>\n        /// <param name=\"selector\">A transform function to apply (map) to each element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the transform function on each element (mapping) of source.</returns>\n        public static TResult[] Map<T, TResult>(this Span<T> source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new TResult[source.Length];\n            for (int i = 0; i < source.Length; i++)\n            {\n                r[i] = selector(source[i]);\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        ///  Projects each element of a sequence into a new form by incorporating the element's index.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on.</param>\n        /// <param name=\"selector\">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the transform function on each element of source.</returns>\n        public static TResult[] Map<T, TResult>(this Span<T> source, Func<T, int, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new TResult[source.Length];\n            for (int i = 0; i < source.Length; i++)\n            {\n                r[i] = selector(source[i], i);\n            }\n\n            return r;\n        }\n#endif\n\n        // --------------------------  LISTS --------------------------------------------\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form in place.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on (map).</param>\n        /// <param name=\"selector\">A transform function to apply (map) to each element.</param>        \n        public static void MapOrigin<T>(this List<T> source, Func<T, T> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                source[i] = selector(source[i]);\n            }\n        }\n\n        /// <summary>\n        /// Projects each element of a sequence into a new form, in place, by incorporating the element's index.\n        /// The result will change itself <paramref name = \"source\" />\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on.</param>\n        /// <param name=\"selector\">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>        \n        public static void MapOrigin<T>(this List<T> source, Func<T, int, T> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                source[i] = selector(source[i], i);\n            }\n        }\n\n\n        /// <summary>\n        ///  Projects each element of a sequence into a new form. (map in every other language)\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on (map).</param>\n        /// <param name=\"selector\">A transform function to apply (map) to each element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the transform function on each element (mapping) of source.</returns>\n        public static List<TResult> Map<T, TResult>(this List<T> source, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new List<TResult>(source.Count);\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                r.Add(selector(source[i]));\n            }\n\n            return r;\n        }\n\n\n        /// <summary>\n        ///  Projects each element of a sequence into a new form by incorporating the element's index.\n        /// </summary>        \n        /// <param name=\"source\">A sequence of values to invoke a transform function on.</param>\n        /// <param name=\"selector\">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the transform function on each element of source.</returns>\n        public static List<TResult> Map<T, TResult>(this List<T> source, Func<T, int, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new List<TResult>(source.Count);\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                r.Add(selector(source[i], i));\n            }\n\n            return r;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Select.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 05242163f530f56499e08659945839c6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/SelectMany.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  Arrays --------------------------------------------\n\n        /// <summary>\n        /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence.\n        /// Yo dawg, I heard you like sequences.\n        /// </summary>                    \n        /// <param name=\"source\">A sequence of values to project.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence.</returns>\n        public static TResult[] SelectMany<TSource, TResult>(this TSource[] source, Func<TSource, TResult[]> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new List<TResult>(source.Length);\n            for (int i = 0; i < source.Length; i++)\n            {\n                var va = selector(source[i]);\n                for (int j = 0; j < va.Length; j++)\n                {\n                    result.Add(va[j]);\n                }\n            }\n\n            return result.ToArray();\n        }\n\n        /// <summary>\n        /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence\n        /// utilizing the index of each element.\n        /// </summary>                    \n        /// <param name=\"source\">A sequence of values to project.</param>\n        /// <param name=\"selector\">A transform function to apply to each element and it's index.</param>\n        /// <returns>A sequence whose elements are the result of invoking the one-to-many transform function on each element and index of the input sequence.</returns>\n        public static TResult[] SelectMany<TSource, TResult>(this TSource[] source, Func<TSource, int, TResult[]> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new List<TResult>(source.Length);\n            for (int i = 0; i < source.Length; i++)\n            {\n                var va = selector(source[i], i);\n                for (int j = 0; j < va.Length; j++)\n                {\n                    result.Add(va[j]);\n                }\n            }\n\n            return result.ToArray();\n        }\n\n        // --------------------------  this Spans --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence.\n        /// Yo dawg, I heard you like sequences.\n        /// </summary>                    \n        /// <param name=\"source\">A sequence of values to project.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence.</returns>\n        public static TResult[] SelectMany<TSource, TResult>(this Span<TSource> source, Func<TSource, TResult[]> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new List<TResult>(source.Length);\n            for (int i = 0; i < source.Length; i++)\n            {\n                var va = selector(source[i]);\n                for (int j = 0; j < va.Length; j++)\n                {\n                    result.Add(va[j]);\n                }\n            }\n\n            return result.ToArray();\n        }\n\n        /// <summary>\n        /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence\n        /// utilizing the index of each element.\n        /// </summary>                    \n        /// <param name=\"source\">A sequence of values to project.</param>\n        /// <param name=\"selector\">A transform function to apply to each element and it's index.</param>\n        /// <returns>A sequence whose elements are the result of invoking the one-to-many transform function on each element and index of the input sequence.</returns>\n        public static TResult[] SelectMany<TSource, TResult>(this Span<TSource> source, Func<TSource, int, TResult[]> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new List<TResult>(source.Length);\n            for (int i = 0; i < source.Length; i++)\n            {\n                var va = selector(source[i], i);\n                for (int j = 0; j < va.Length; j++)\n                {\n                    result.Add(va[j]);\n                }\n            }\n\n            return result.ToArray();\n        }\n#endif\n        // --------------------------  LISTS --------------------------------------------\n\n        /// <summary>\n        /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence.\n        /// Yo dawg, I heard you like sequences.\n        /// </summary>                    \n        /// <param name=\"source\">A sequence of values to project.</param>\n        /// <param name=\"selector\">A transform function to apply to each element.</param>\n        /// <returns>A sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence.</returns>\n        public static List<TResult> SelectMany<TSource, TResult>(this List<TSource> source, Func<TSource, List<TResult>> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new List<TResult>(source.Count);\n            for (int i = 0; i < source.Count; i++)\n            {\n                var va = selector(source[i]);\n                for (int j = 0; j < va.Count; j++)\n                {\n                    result.Add(va[j]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Projects each element of a sequence to another sequence and flattens the resulting sequences into one sequence\n        /// utilizing the index of each element.\n        /// </summary>                    \n        /// <param name=\"source\">A sequence of values to project.</param>\n        /// <param name=\"selector\">A transform function to apply to each element and it's index.</param>\n        /// <returns>A sequence whose elements are the result of invoking the one-to-many transform function on each element and index of the input sequence.</returns>\n        public static List<TResult> SelectMany<TSource, TResult>(this List<TSource> source, Func<TSource, int, List<TResult>> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new List<TResult>(source.Count);\n            for (int i = 0; i < source.Count; i++)\n            {\n                var va = selector(source[i], i);\n                for (int j = 0; j < va.Count; j++)\n                {\n                    result.Add(va[j]);\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/SelectMany.cs.meta",
    "content": "fileFormatVersion: 2\nguid: be9b005d1735e8b4e9c87398cfacf2c2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/SelectWhere.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS --------------------------------------------\n\n        /// <summary>\n        /// Combines Select and Where into a single call for optimal\n        /// performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter and select</param>\n        /// <param name=\"selector\">The transformation to apply before filtering.</param>\n        /// <param name=\"predicate\">The predicate with which to filter result.</param>\n        /// <returns>A sequence transformed and then filtered by selector and predicate.</returns>\n        public static TResult[] MapFilter<T, TResult>(this T[] source, Func<T, TResult> selector, Func<TResult, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var s = selector(source[i]);\n                if (predicate(s))\n                {\n                    result[idx] = s;\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Select and Where with indexes into a single call for optimal\n        /// performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter and select</param>\n        /// <param name=\"selector\">The transformation with index to apply before filtering.</param>\n        /// <param name=\"predicate\">The predicate with index with which to filter result.</param>\n        /// <returns>A sequence transformed and then filtered by selector and predicate with indexes.</returns>\n        public static TResult[] MapFilter<T, TResult>(this T[] source, Func<T, int, TResult> selector, Func<TResult, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var s = selector(source[i], i);\n                if (predicate(s, i))\n                {\n                    result[idx] = s;\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        // --------------------------  this Spans --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Combines Select and Where into a single call for optimal\n        /// performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter and select</param>\n        /// <param name=\"selector\">The transformation to apply before filtering.</param>\n        /// <param name=\"predicate\">The predicate with which to filter result.</param>\n        /// <returns>A sequence transformed and then filtered by selector and predicate.</returns>\n        public static TResult[] MapFilter<T, TResult>(this Span<T> source, Func<T, TResult> selector, Func<TResult, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var s = selector(source[i]);\n                if (predicate(s))\n                {\n                    result[idx] = s;\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Select and Where with indexes into a single call for optimal\n        /// performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter and select</param>\n        /// <param name=\"selector\">The transformation with index to apply before filtering.</param>\n        /// <param name=\"predicate\">The predicate with index with which to filter result.</param>\n        /// <returns>A sequence transformed and then filtered by selector and predicate with indexes.</returns>\n        public static TResult[] MapFilter<T, TResult>(this Span<T> source, Func<T, int, TResult> selector, Func<TResult, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                var s = selector(source[i], i);\n                if (predicate(s, i))\n                {\n                    result[idx] = s;\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n#endif\n\n        // --------------------------  LISTS --------------------------------------------\n\n        /// <summary>\n        /// Combines Select and Where into a single call for optimal\n        /// performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter and select</param>\n        /// <param name=\"selector\">The transformation to apply before filtering.</param>\n        /// <param name=\"predicate\">The predicate with which to filter result.</param>\n        /// <returns>A sequence transformed and then filtered by selector and predicate.</returns>\n        public static List<TResult> MapFilter<T, TResult>(this List<T> source, Func<T, TResult> selector, Func<TResult, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var r = new List<TResult>();\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = selector(source[i]);\n                if (predicate(s)) r.Add(s);\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Combines Select and Where with indexes into a single call for optimal\n        /// performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter and select</param>\n        /// <param name=\"selector\">The transformation with index to apply before filtering.</param>\n        /// <param name=\"predicate\">The predicate with index with which to filter result.</param>\n        /// <returns>A sequence transformed and then filtered by selector and predicate with indexes.</returns>\n        public static List<TResult> MapFilter<T, TResult>(this List<T> source, Func<T, int, TResult> selector, Func<TResult, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var r = new List<TResult>();\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = selector(source[i], i);\n                if (predicate(s, i)) r.Add(s);\n            }\n\n            return r;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/SelectWhere.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9723c36dde8b1fb44baf0a42e21c0e1d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/SequenceEqual.cs",
    "content": "﻿using System.Collections.Generic;\nusing System;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>     \n        public static bool SequenceEqual<T>(this T[] first, T[] second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Length != second.Length) return false;\n            if (first == second) return true;\n\n            for (int i = 0; i < first.Length; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>An array of integers, where the value corresponds to IComparer.Compare indicating less than, greater than, or equals</returns>     \n        public static int[] SequenceCompare<T>(this T[] first, T[] second, IComparer<T> comparer = null)\n        {\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (comparer == null)\n            {\n                comparer = Comparer<T>.Default;\n            }\n\n            if (first.Length != second.Length) throw new NotSupportedException();\n\n            var result = new int[first.Length];\n            for (int i = 0; i < first.Length; i++)\n            {\n                result[i] = comparer.Compare(first[i], second[i]);\n            }\n\n            return result;\n        }\n\n\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>\n        public static bool SequenceEqual<T>(this T[] first, List<T> second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Length != second.Count) return false;\n\n            for (int i = 0; i < first.Length; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>\n        public static bool SequenceEqual<T>(this List<T> first, T[] second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Count != second.Length) return false;\n\n            for (int i = 0; i < first.Count; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n\n        /*---- Spans ----*/\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>     \n        public static bool SequenceEqual<T>(this Span<T> first, Span<T> second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Length != second.Length) return false;\n            if (first == second) return true;\n\n            for (int i = 0; i < first.Length; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n\n\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>\n        public static bool SequenceEqual<T>(this Span<T> first, List<T> second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Length != second.Count) return false;\n\n            for (int i = 0; i < first.Length; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>\n        public static bool SequenceEqual<T>(this List<T> first, Span<T> second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Count != second.Length) return false;\n\n            for (int i = 0; i < first.Count; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n#endif\n\n        /* ------------ List ---------------- */\n\n        /// <summary>\n        /// Determines whether two sequences are equal by comparing the elements by using the \n        /// provided comparer or the default equality comparer for their type if none is provided.\n        /// </summary>        \n        /// <param name=\"first\">A sequence to compare to second.</param>\n        /// <param name=\"second\">A sequence to compare to first.</param>\n        /// <param name=\"comparer\">An optional Comparer to use for the comparison.</param>\n        /// <returns>true of the two sources are of equal length and their corresponding \n        /// elements are equal according to the equality comparer. Otherwise, false.</returns>\n        public static bool SequenceEqual<T>(this List<T> first, List<T> second, IEqualityComparer<T> comparer = null)\n        {\n            if (comparer == null)\n            {\n                comparer = EqualityComparer<T>.Default;\n            }\n\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (first.Count != second.Count) return false;\n            if (first == second) return true;\n\n            for (int i = 0; i < first.Count; i++)\n            {\n                if (!comparer.Equals(first[i], second[i])) return false;\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/SequenceEqual.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b325f40656270884781d1acfe34ec446\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Single.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------- Arrays ----------------------------\n\n        /// <summary>\n        /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the single element of</param>\n        /// <returns>The single element of the input sequence or default if no elements exist.</returns>\n        public static T Single<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (source.Length > 1) throw new InvalidOperationException(\"Source sequence contains more than one element.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence, or the default if no elements exist, and throws an exception if there is not exactly one element in the sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the single element of</param>\n        /// <returns>The single element of the input sequence</returns>\n        public static T SingleOrDefault<T>(this T[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) return default(T);\n\n            if (source.Length > 1) throw new InvalidOperationException(\"Source sequence contains more than one element.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return a single element from.</param>\n        /// <param name=\"predicate\">A function to test an element for a condition.</param>\n        /// <returns>The single element of the input sequence that satisfies a condition.</returns>\n        public static T Single<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T result = default(T);\n            bool foundMatch = false;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    if (foundMatch) throw new InvalidOperationException(\"Sequence contains more than one matching element\");\n\n                    result = source[i];\n                    foundMatch = true;\n                }\n            }\n\n            if (foundMatch) return result;\n\n            throw new InvalidOperationException(\"Sequence contains no matching element\");\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence that satisfies a specified condition, or a default value if\n        /// no such element exists, and throws an exception if more than one such element exists.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return a single element from.</param>\n        /// <param name=\"predicate\">A function to test an element for a condition.</param>\n        /// <returns>The single element of the input sequence that satisfies a condition or default value if no such element is found.</returns>\n        public static T SingleOrDefault<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T result = default(T);\n            bool foundMatch = false;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    if (foundMatch) throw new InvalidOperationException(\"Sequence contains more than one matching element\");\n\n                    result = source[i];\n                    foundMatch = true;\n                }\n            }\n\n            return result;\n        }\n\n        // --------------------------- Spans ----------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the single element of</param>\n        /// <returns>The single element of the input sequence or default if no elements exist.</returns>\n        public static T Single<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (source.Length > 1) throw new InvalidOperationException(\"Source sequence contains more than one element.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence, or the default if no elements exist, and throws an exception if there is not exactly one element in the sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the single element of</param>\n        /// <returns>The single element of the input sequence</returns>\n        public static T SingleOrDefault<T>(this Span<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Length == 0) return default(T);\n\n            if (source.Length > 1) throw new InvalidOperationException(\"Source sequence contains more than one element.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return a single element from.</param>\n        /// <param name=\"predicate\">A function to test an element for a condition.</param>\n        /// <returns>The single element of the input sequence that satisfies a condition.</returns>\n        public static T Single<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T result = default(T);\n            bool foundMatch = false;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    if (foundMatch) throw new InvalidOperationException(\"Sequence contains more than one matching element\");\n\n                    result = source[i];\n                    foundMatch = true;\n                }\n            }\n\n            if (foundMatch) return result;\n\n            throw new InvalidOperationException(\"Sequence contains no matching element\");\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence that satisfies a specified condition, or a default value if\n        /// no such element exists, and throws an exception if more than one such element exists.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return a single element from.</param>\n        /// <param name=\"predicate\">A function to test an element for a condition.</param>\n        /// <returns>The single element of the input sequence that satisfies a condition or default value if no such element is found.</returns>\n        public static T SingleOrDefault<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T result = default(T);\n            bool foundMatch = false;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    if (foundMatch) throw new InvalidOperationException(\"Sequence contains more than one matching element\");\n\n                    result = source[i];\n                    foundMatch = true;\n                }\n            }\n\n            return result;\n        }\n#endif\n\n        // --------------------------- Lists ----------------------------\n\n        /// <summary>\n        /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the single element of</param>\n        /// <returns>The single element of the input sequence</returns>\n        public static T Single<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n            if (source.Count > 1) throw new InvalidOperationException(\"Source sequence contains more than one element.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence, or default if no elements exist, and throws an exception if there is not exactly one element in the sequence.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return the single element of</param>\n        /// <returns>The single element of the input sequence or default if no elements exist.</returns>\n        public static T SingleOrDefault<T>(this List<T> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (source.Count == 0) return default(T);\n\n            if (source.Count > 1) throw new InvalidOperationException(\"Source sequence contains more than one element.\");\n\n            return source[0];\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return a single element from.</param>\n        /// <param name=\"predicate\">A function to test an element for a condition.</param>\n        /// <returns>The single element of the input sequence that satisfies a condition.</returns>\n        public static T Single<T>(this List<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T result = default(T);\n            bool foundMatch = false;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    if (foundMatch) throw new InvalidOperationException(\"Sequence contains more than one matching element\");\n\n                    result = source[i];\n                    foundMatch = true;\n                }\n            }\n\n            if (foundMatch) return result;\n\n            throw new InvalidOperationException(\"Sequence contains no matching element\");\n        }\n\n        /// <summary>\n        /// Returns the only element of a sequence that satisfies a specified condition, or a default value if\n        /// no such element exists, and throws an exception if more than one such element exists.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return a single element from.</param>\n        /// <param name=\"predicate\">A function to test an element for a condition.</param>\n        /// <returns>The single element of the input sequence that satisfies a condition or default value if no such element is found.</returns>\n        public static T SingleOrDefault<T>(this List<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T result = default(T);\n            bool foundMatch = false;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    if (foundMatch) throw new InvalidOperationException(\"Sequence contains more than one matching element\");\n\n                    result = source[i];\n                    foundMatch = true;\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Single.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d320db55c90ee5e409eda1e9b4086486\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Skip.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Bypasses a specified number of elements in a sequence and then returns the remaining elements.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"count\">The number of elements to skip before returning the remaining elements.</param>\n        /// <returns>A sequence that contains the elements that occur after the specified index in the input sequence.</returns>\n        public static T[] Skip<T>(this T[] source, int count)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (count < 0)\n            {\n                count = 0;\n            }\n            else if (count > source.Length)\n            {\n                return new T[0];\n            }\n\n            var result = new T[source.Length - count];\n            Array.Copy(source,\n                count,\n                result,\n                0,\n                result.Length);\n            return result;\n        }\n\n        /// <summary>\n        ///  Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.\n        /// </summary>\n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.</returns>\n        public static T[] SkipWhile<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int i = 0;\n            for (; i < source.Length; i++)\n            {\n                if (!predicate(source[i])) break;\n            }\n\n            var result = new T[source.Length - i];\n            Array.Copy(source,\n                i,\n                result,\n                0,\n                result.Length);\n            return result;\n        }\n\n        /*------------- SPans ---------------- */\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Bypasses a specified number of elements in a sequence and then returns the remaining elements.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"count\">The number of elements to skip before returning the remaining elements.</param>\n        /// <returns>A sequence that contains the elements that occur after the specified index in the input sequence.</returns>\n        public static T[] Skip<T>(this Span<T> source, int count)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (count < 0)\n            {\n                count = 0;\n            }\n            else if (count > source.Length)\n            {\n                return new T[0];\n            }\n\n            var result = new T[source.Length - count];\n            for (int i = count; i < source.Length; i++)\n            {\n                result[i - count] = source[i];\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        ///  Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.\n        /// </summary>\n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.</returns>\n        public static T[] SkipWhile<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (; count < source.Length; count++)\n            {\n                if (!predicate(source[count])) break;\n            }\n\n            var result = new T[source.Length - count];\n            for (int i = count; i < source.Length; i++)\n            {\n                result[i - count] = source[i];\n            }\n\n            return result;\n        }\n#endif\n\n\n        // ------------- Lists ----------------\n\n        /// <summary>\n        /// Bypasses a specified number of elements in a sequence and then returns the remaining elements.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"count\">The number of elements to skip before returning the remaining elements.</param>\n        /// <returns>A sequence that contains the elements that occur after the specified index in the input sequence.</returns>\n        public static List<T> Skip<T>(this List<T> source, int count)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (count < 0)\n            {\n                count = 0;\n            }\n            else if (count > source.Count)\n            {\n                return new List<T>();\n            }\n\n            var result = new List<T>(source.Count - count);\n            for (int i = count; i < source.Count; i++)\n            {\n                result.Add(source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        ///  Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.\n        /// </summary>\n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.</returns>\n        public static List<T> SkipWhile<T>(this List<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int i = 0;\n            for (; i < source.Count; i++)\n            {\n                if (!predicate(source[i]))\n                {\n                    break;\n                }\n            }\n\n            var result = new List<T>(source.Count - i);\n            for (; i < source.Count; i++)\n            {\n                result.Add(source[i]);\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Skip.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9eac67b4bf84bcb4bba4ac6b9eeb25f4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Sum.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static int Sum(this int[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static int Sum<T>(this T[] source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static long Sum(this long[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static long Sum<T>(this T[] source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static float Sum(this float[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n\n            foreach (var v in source)\n            {\n                sum += v;\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static float Sum<T>(this T[] source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                sum += selector(v);\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static double Sum(this double[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                sum += v;\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static double Sum<T>(this T[] source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                sum += selector(v);\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static decimal Sum(this decimal[] source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            decimal sum = 0;\n\n            foreach (var v in source)\n            {\n                sum += v;\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static decimal Sum<T>(this T[] source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal sum = 0;\n            foreach (var v in source)\n            {\n                sum += selector(v);\n            }\n\n            return sum;\n        }\n\n        /*---- Spans ---*/\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static int Sum(this Span<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static int Sum<T>(this Span<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static long Sum(this Span<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static long Sum<T>(this Span<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static float Sum(this Span<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n\n            foreach (var v in source)\n            {\n                sum += v;\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static float Sum<T>(this Span<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                sum += selector(v);\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static double Sum(this Span<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                sum += v;\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static double Sum<T>(this Span<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                sum += selector(v);\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static decimal Sum(this Span<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            decimal sum = 0;\n\n            foreach (var v in source)\n            {\n                sum += v;\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static decimal Sum<T>(this Span<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal sum = 0;\n            foreach (var v in source)\n            {\n                sum += selector(v);\n            }\n\n            return sum;\n        }\n#endif\n\n        // --------------------------  LISTS  --------------------------------------------\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static int Sum(this List<int> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            int sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static int Sum<T>(this List<T> source, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static long Sum(this List<long> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += source[i];\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static long Sum<T>(this List<T> source, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    sum += selector(source[i]);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static float Sum(this List<float> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += source[i];\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static float Sum<T>(this List<T> source, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static double Sum(this List<double> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static double Sum<T>(this List<T> source, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds a sequence of values.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static decimal Sum(this List<decimal> source)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += source[i];\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Adds the transformed sequence of elements.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static decimal Sum<T>(this List<T> source, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                sum += selector(source[i]);\n            }\n\n            return sum;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Sum.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a400c981f3bcb7544825ed19bd6795f9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Take.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Returns a specified number of contiguous elements from the start of a sequence.\n        /// </summary>        \n        /// <param name=\"source\">The sequence to return elements from.</param>\n        /// <param name=\"count\">The number of elements to return.</param>\n        /// <returns>A sequence that contains the specified number of elements from the start of the input sequence.</returns>\n        public static T[] Take<T>(this T[] source, int count)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (count < 0)\n            {\n                count = 0;\n            }\n            else if (count > source.Length)\n            {\n                count = source.Length;\n            }\n\n            var result = new T[count];\n            Array.Copy(source,\n                0,\n                result,\n                0,\n                count);\n            return result;\n        }\n\n        /// <summary>\n        /// Returns elements from a sequence as long as a specified condition is true.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes.</returns>\n        public static T[] TakeWhile<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (; count < source.Length; count++)\n            {\n                if (!predicate(source[count]))\n                    break;\n            }\n\n            var result = new T[count];\n            Array.Copy(source,\n                0,\n                result,\n                0,\n                count);\n            return result;\n        }\n\n        /// <summary>\n        /// Returns elements from a sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function.\n        /// </summary>        \n        /// <param name=\"source\">The sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each source element for a condition; the second parameter of the function represents the index of the source element.</param>\n        /// <returns>A sequence that contains elements from the input sequence that occur before the element at which the test no longer passes.</returns>\n        public static T[] TakeWhile<T>(this T[] source, Func<T, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (; count < source.Length; count++)\n            {\n                if (!predicate(source[count], count))\n                    break;\n            }\n\n            var result = new T[count];\n            Array.Copy(source,\n                0,\n                result,\n                0,\n                count);\n            return result;\n        }\n\n        /*---- spans ---- */\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Returns a specified number of contiguous elements from the start of a sequence.\n        /// </summary>        \n        /// <param name=\"source\">The sequence to return elements from.</param>\n        /// <param name=\"count\">The number of elements to return.</param>\n        /// <returns>A sequence that contains the specified number of elements from the start of the input sequence.</returns>\n        public static T[] Take<T>(this Span<T> source, int count)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (count < 0)\n            {\n                count = 0;\n            }\n            else if (count > source.Length)\n            {\n                count = source.Length;\n            }\n\n            var result = new T[count];\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = source[i];\n            }\n\n            return result;\n        }\n\n\n        /// <summary>\n        /// Returns elements from a sequence as long as a specified condition is true.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes.</returns>\n        public static T[] TakeWhile<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (; count < source.Length; count++)\n            {\n                if (!predicate(source[count]))\n                    break;\n            }\n\n            var result = new T[count];\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = source[i];\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns elements from a sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function.\n        /// </summary>        \n        /// <param name=\"source\">The sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each source element for a condition; the second parameter of the function represents the index of the source element.</param>\n        /// <returns>A sequence that contains elements from the input sequence that occur before the element at which the test no longer passes.</returns>\n        public static T[] TakeWhile<T>(this Span<T> source, Func<T, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            int count = 0;\n            for (; count < source.Length; count++)\n            {\n                if (!predicate(source[count], count))\n                    break;\n            }\n\n            var result = new T[count];\n            for (int i = 0; i < result.Length; i++)\n            {\n                result[i] = source[i];\n            }\n\n            return result;\n        }\n#endif\n\n\n        // ------------- Lists ----------------\n\n        /// <summary>\n        /// Returns a specified number of contiguous elements from the start of a sequence.\n        /// </summary>        \n        /// <param name=\"source\">The sequence to return elements from.</param>\n        /// <param name=\"count\">The number of elements to return.</param>\n        /// <returns>A sequence that contains the specified number of elements from the start of the input sequence.</returns>\n        public static List<T> Take<T>(this List<T> source, int count)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (count < 0)\n            {\n                count = 0;\n            }\n            else if (count > source.Count)\n            {\n                count = source.Count;\n            }\n\n            var result = new List<T>(count);\n            for (int i = 0; i < count; i++)\n            {\n                result.Add(source[i]);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns elements from a sequence as long as a specified condition is true.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains the elements from the input sequence that occur before the element at which the test no longer passes.</returns>\n        public static List<T> TakeWhile<T>(this List<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = new List<T>();\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result.Add(source[i]);\n                }\n                else\n                {\n                    return result;\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Returns elements from a sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function.\n        /// </summary>        \n        /// <param name=\"source\">The sequence to return elements from.</param>\n        /// <param name=\"predicate\">A function to test each source element for a condition; the second parameter of the function represents the index of the source element.</param>\n        /// <returns>A sequence that contains elements from the input sequence that occur before the element at which the test no longer passes.</returns>\n        public static List<T> TakeWhile<T>(this List<T> source, Func<T, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = new List<T>();\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i], i))\n                    result.Add(source[i]);\n                else\n                    return result;\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Take.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0cc2e55e421b8744b8e07aac567cd8f1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Utils/ComparerMagic.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\nnamespace VirtueSky.Linq\n{\n    //Takes a comparer, and creates a reverse comparer, for Descending sorts\n    internal sealed class ComparerReverser<T> : IComparer<T>\n    {\n        private readonly IComparer<T> _wrappedComparer;\n\n        public ComparerReverser(IComparer<T> wrappedComparer)\n        {\n            this._wrappedComparer = wrappedComparer;\n        }\n#if !(UNITY_4 || UNITY_5)\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n#endif\n        public int Compare(T x, T y)\n        {\n            return _wrappedComparer.Compare(y, x);\n        }\n    }\n\n\n    internal static class ComparerExtensions\n    {\n        // Lets us reverse a comparere with comparer.Reverse();\n        public static IComparer<T> Reverse<T>(this IComparer<T> comparer)\n        {\n            return new ComparerReverser<T>(comparer);\n        }\n    }\n\n    internal sealed class LambdaComparer<T, TU> : IComparer<T>\n    {\n        IComparer<TU> _comparer;\n        Func<T, TU> _selector;\n\n        public LambdaComparer(Func<T, TU> selector, IComparer<TU> comparer)\n        {\n            this._comparer = comparer;\n            this._selector = selector;\n        }\n#if !(UNITY_4 || UNITY_5)\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n#endif\n        public int Compare(T x, T y)\n        {\n            return _comparer.Compare(_selector(x), _selector(y));\n        }\n    }\n\n    internal sealed class ReverseLambdaComparer<T, TU> : IComparer<T>\n    {\n        IComparer<TU> _comparer;\n        Func<T, TU> _selector;\n\n        public ReverseLambdaComparer(Func<T, TU> selector, IComparer<TU> comparer)\n        {\n            this._comparer = comparer;\n            this._selector = selector;\n        }\n#if !(UNITY_4 || UNITY_5)\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n#endif\n        public int Compare(T x, T y)\n        {\n            return _comparer.Compare(_selector(y), _selector(x));\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Utils/ComparerMagic.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 66557ee940d37f34aab35fea89d904df\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Utils/CustomPartition.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public class EmptyOrderablePartitioner<T> : OrderablePartitioner<T>\n    {\n        // Constructor just grabs the collection to wrap\n        public EmptyOrderablePartitioner()\n            : base(true, true, true)\n        {\n        }\n\n        public override IList<IEnumerator<KeyValuePair<long, T>>> GetOrderablePartitions(int partitionCount)\n        {\n            return new List<IEnumerator<KeyValuePair<long, T>>>();\n        }\n\n\n        public override IEnumerable<KeyValuePair<long, T>> GetOrderableDynamicPartitions()\n        {\n            return new List<KeyValuePair<long, T>>();\n        }\n\n        // Must be set to true if GetDynamicPartitions() is supported.\n        public override bool SupportsDynamicPartitions\n        {\n            get { return true; }\n        }\n    }\n\n    internal static class CustomPartition\n    {\n        public static OrderablePartitioner<Tuple<int, int>> MakePartition(int len, int? batchSize)\n        {\n            if (len == 0) return new EmptyOrderablePartitioner<Tuple<int, int>>();\n\n            if (batchSize == null)\n            {\n                return Partitioner.Create(0, len);\n            }\n            else\n            {\n                return Partitioner.Create(0, len, batchSize.Value);\n            }\n        }\n\n        public static OrderablePartitioner<Tuple<int, int>> MakeSimdPartition(int len, int chunkSize, int? batchSize)\n        {\n            if (len == 0) return new EmptyOrderablePartitioner<Tuple<int, int>>();\n\n            int chunkLen = len - len % chunkSize;\n            int numChunks = chunkLen / chunkSize;\n            if (batchSize == null)\n            {\n                return Partitioner.Create(0, numChunks, numChunks / Environment.ProcessorCount);\n            }\n            else\n            {\n                return Partitioner.Create(0, numChunks, batchSize.Value);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Utils/CustomPartition.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dde1a3193124a35428d1cb52f5911b07\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Utils/GenericOperators.cs",
    "content": "﻿using System;\nusing System.Runtime.CompilerServices;\n\n/*\n\n    C# has no way to constrain a generic to only primitive types.\n    You can only constrain them to value types via:\n        where T : struct\n    All primitives are value types but not all value types are\n    primitives. Thus, when you try to do operations like + > < ==\n    on generic value types, you get a compiler error.  These methods\n    work around that by checking the type, casting, and performing the\n    operation.  The JIT elides all of the non relevant bits of the If statement\n    for each generic type, so this is remarkably still fast.  Since these are\n    only used for the SIMD specific operations, and the SIMD library\n    works exactly this way as well, it does not add any problems that\n    don't already exist when you use .NET SIMD.  Which is, if you create a\n    Vector<T> where T is a non primitive value type, you will get a runtime error.\n */\nnamespace VirtueSky.Linq\n{\n    internal static class GenericOperators\n    {\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T Add<T>(T a, T b)\n        {\n            if (typeof(T) == typeof(byte))\n            {\n                return (T)(object)((byte)(object)a + (byte)(object)b);\n            }\n\n            if (typeof(T) == typeof(sbyte))\n            {\n                return (T)(object)((sbyte)(object)a + (sbyte)(object)b);\n            }\n\n            if (typeof(T) == typeof(ushort))\n            {\n                return (T)(object)((ushort)(object)a + (ushort)(object)b);\n            }\n\n            if (typeof(T) == typeof(short))\n            {\n                return (T)(object)((short)(object)a + (short)(object)b);\n            }\n\n            if (typeof(T) == typeof(uint))\n            {\n                return (T)(object)((uint)(object)a + (uint)(object)b);\n            }\n\n            if (typeof(T) == typeof(int))\n            {\n                return (T)(object)((int)(object)a + (int)(object)b);\n            }\n\n            if (typeof(T) == typeof(ulong))\n            {\n                return (T)(object)((ulong)(object)a + (ulong)(object)b);\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                return (T)(object)((long)(object)a + (long)(object)b);\n            }\n\n            if (typeof(T) == typeof(float))\n            {\n                return (T)(object)((float)(object)a + (float)(object)b);\n            }\n\n            if (typeof(T) == typeof(double))\n            {\n                return (T)(object)((double)(object)a + (double)(object)b);\n            }\n\n            throw new NotSupportedException(\"Nope\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool GreaterThan<T>(T a, T b)\n        {\n            if (typeof(T) == typeof(byte))\n            {\n                return ((byte)(object)a > (byte)(object)b);\n            }\n\n            if (typeof(T) == typeof(sbyte))\n            {\n                return ((sbyte)(object)a > (sbyte)(object)b);\n            }\n\n            if (typeof(T) == typeof(ushort))\n            {\n                return ((ushort)(object)a > (ushort)(object)b);\n            }\n\n            if (typeof(T) == typeof(short))\n            {\n                return ((short)(object)a > (short)(object)b);\n            }\n\n            if (typeof(T) == typeof(uint))\n            {\n                return ((uint)(object)a > (uint)(object)b);\n            }\n\n            if (typeof(T) == typeof(int))\n            {\n                return ((int)(object)a > (int)(object)b);\n            }\n\n            if (typeof(T) == typeof(ulong))\n            {\n                return ((ulong)(object)a > (ulong)(object)b);\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                return ((long)(object)a > (long)(object)b);\n            }\n\n            if (typeof(T) == typeof(float))\n            {\n                return ((float)(object)a > (float)(object)b);\n            }\n\n            if (typeof(T) == typeof(double))\n            {\n                return ((double)(object)a > (double)(object)b);\n            }\n\n            throw new NotSupportedException(\"Nope\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool Equals<T>(T a, T b)\n        {\n            if (typeof(T) == typeof(byte))\n            {\n                return ((byte)(object)a == (byte)(object)b);\n            }\n\n            if (typeof(T) == typeof(sbyte))\n            {\n                return ((sbyte)(object)a == (sbyte)(object)b);\n            }\n\n            if (typeof(T) == typeof(ushort))\n            {\n                return ((ushort)(object)a == (ushort)(object)b);\n            }\n\n            if (typeof(T) == typeof(short))\n            {\n                return ((short)(object)a == (short)(object)b);\n            }\n\n            if (typeof(T) == typeof(uint))\n            {\n                return ((uint)(object)a == (uint)(object)b);\n            }\n\n            if (typeof(T) == typeof(int))\n            {\n                return ((int)(object)a == (int)(object)b);\n            }\n\n            if (typeof(T) == typeof(ulong))\n            {\n                return ((ulong)(object)a == (ulong)(object)b);\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                return ((long)(object)a == (long)(object)b);\n            }\n\n            if (typeof(T) == typeof(float))\n            {\n                return ((float)(object)a == (float)(object)b);\n            }\n\n            if (typeof(T) == typeof(double))\n            {\n                return ((double)(object)a == (double)(object)b);\n            }\n\n            throw new NotSupportedException(\"Nope\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool LessThan<T>(T a, T b)\n        {\n            if (typeof(T) == typeof(byte))\n            {\n                return ((byte)(object)a < (byte)(object)b);\n            }\n\n            if (typeof(T) == typeof(sbyte))\n            {\n                return ((sbyte)(object)a < (sbyte)(object)b);\n            }\n\n            if (typeof(T) == typeof(ushort))\n            {\n                return ((ushort)(object)a < (ushort)(object)b);\n            }\n\n            if (typeof(T) == typeof(short))\n            {\n                return ((short)(object)a < (short)(object)b);\n            }\n\n            if (typeof(T) == typeof(uint))\n            {\n                return ((uint)(object)a < (uint)(object)b);\n            }\n\n            if (typeof(T) == typeof(int))\n            {\n                return ((int)(object)a < (int)(object)b);\n            }\n\n            if (typeof(T) == typeof(ulong))\n            {\n                return ((ulong)(object)a < (ulong)(object)b);\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                return ((long)(object)a < (long)(object)b);\n            }\n\n            if (typeof(T) == typeof(float))\n            {\n                return ((float)(object)a < (float)(object)b);\n            }\n\n            if (typeof(T) == typeof(double))\n            {\n                return ((double)(object)a < (double)(object)b);\n            }\n\n            throw new NotSupportedException(\"Nope\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static double Divide<T>(T a, double b)\n        {\n            if (typeof(T) == typeof(byte))\n            {\n                return (double)(object)((byte)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(sbyte))\n            {\n                return (double)(object)((sbyte)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(ushort))\n            {\n                return (double)(object)((ushort)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(short))\n            {\n                return (double)(object)((short)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(uint))\n            {\n                return (double)(object)((uint)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(int))\n            {\n                return (double)(object)((int)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(ulong))\n            {\n                return (double)(object)((ulong)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                return (double)(object)((long)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(float))\n            {\n                return (double)(object)((float)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(double))\n            {\n                return (double)(object)((double)(object)a / b);\n            }\n\n            throw new NotSupportedException(\"Nope\");\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float DivideFloat<T>(T a, float b)\n        {\n            if (typeof(T) == typeof(byte))\n            {\n                return (float)(object)((byte)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(sbyte))\n            {\n                return (float)(object)((sbyte)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(ushort))\n            {\n                return (float)(object)((ushort)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(short))\n            {\n                return (float)(object)((short)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(uint))\n            {\n                return (float)(object)((uint)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(int))\n            {\n                return (float)(object)((int)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(ulong))\n            {\n                return (float)(object)((ulong)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(long))\n            {\n                return (float)(object)((long)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(float))\n            {\n                return (float)(object)((float)(object)a / b);\n            }\n\n            if (typeof(T) == typeof(double))\n            {\n                return (float)(object)((double)(object)a / b);\n            }\n\n            throw new NotSupportedException(\"Nope\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Utils/GenericOperators.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fe36c4d7b07bf2e4bb00c45caf6c9996\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Utils/SliceHelper.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Linq\n{\n    public static class SliceHelper\n    {\n#if UNITY_2021_3_OR_NEWER\n        public static Span<T> Slice<T>(this T[] array, int start, int len)\n        {\n            return array.AsSpan().Slice(start, len);\n        }\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Utils/SliceHelper.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 619337f0dba031740b61516a6273a48d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Utils.meta",
    "content": "fileFormatVersion: 2\nguid: bb0d335b166120842bf598442f1444cd\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/VirtueSky.Sunflower.Linq.asmdef",
    "content": "{\n    \"name\": \"VirtueSky.Sunflower.Linq\",\n    \"rootNamespace\": \"\",\n    \"references\": [],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Linq/VirtueSky.Sunflower.Linq.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: efdee36e63e4ce34a91071531ec746c1\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Where.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS --------------------------------------------\n\n        /// <summary>\n        /// Filters a sequence of values based on a predicate.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to filter.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains elements from the input sequence that satisfy the condition.</returns>        \n        public static T[] Filter<T>(this T[] source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T[] result = new T[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result[idx] = source[i];\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        /// <summary>\n        /// Filters a sequence of values based on a predicate that includes the index in it's logic.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to filter.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition along with the element's index.</param>\n        /// <returns>A sequence that contains elements from the input sequence that satisfy the condition.</returns>\n        public static T[] Filter<T>(this T[] source, Func<T, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n\n            T[] result = new T[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result[idx] = source[i];\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        // --------------------------  Spans --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Filters a sequence of values based on a predicate.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to filter.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains elements from the input sequence that satisfy the condition.</returns>        \n        public static T[] Filter<T>(this Span<T> source, Func<T, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            T[] result = new T[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result[idx] = source[i];\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        /// <summary>\n        /// Filters a sequence of values based on a predicate that includes the index in it's logic.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to filter.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition along with the element's index.</param>\n        /// <returns>A sequence that contains elements from the input sequence that satisfy the condition.</returns>\n        public static T[] Filter<T>(this Span<T> source, Func<T, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n\n            T[] result = new T[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result[idx] = source[i];\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n#endif\n\n        // --------------------------  LISTS --------------------------------------------\n\n        /// <summary>\n        /// Filters a sequence of values based on a predicate.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to filter.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition.</param>\n        /// <returns>A sequence that contains elements from the input sequence that satisfy the condition.</returns>\n        public static List<T> Filter<T>(this List<T> source, Predicate<T> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            return source.FindAll(predicate);\n        }\n\n\n        /// <summary>\n        /// Filters a sequence of values based on a predicate that includes the index in it's logic.\n        /// </summary>        \n        /// <param name=\"source\">A sequence to filter.</param>\n        /// <param name=\"predicate\">A function to test each element for a condition along with the element's index.</param>\n        /// <returns>A sequence that contains elements from the input sequence that satisfy the condition.</returns>\n        public static List<T> Filter<T>(this List<T> source, Func<T, int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            List<T> r = new List<T>();\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i], i)) r.Add(source[i]);\n            }\n\n            return r;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Where.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1b05f1b5de1c9034ea282fb161088459\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/WhereAggregate.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // ----------------------------- Arrays ------------------\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static T FilterReduce<T>(this T[] source, Func<T, bool> predicate, Func<T, T, T> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            var result = default(T);\n\n            int i = 0;\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result = source[i];\n                    i++;\n                    break;\n                }\n            }\n\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result = func(result, source[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate with index for optimal performance\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence and it's index with.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static T FilterReduce<T>(this T[] source, Func<T, int, bool> predicate, Func<T, T, T> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = default(T);\n\n            int i = 0;\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result = source[i];\n                    i++;\n                    break;\n                }\n            }\n\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result = func(result, source[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance with a starting seed.\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"seed\">The initial value to aggregate on.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static TAccumulate FilterReduce<TSource, TAccumulate>(\n            this TSource[] source,\n            Func<TSource, bool> predicate,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            TAccumulate result = seed;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                    result = func(result, v);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance with a starting seed and a result transformation.\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"seed\">The initial value to aggregate on.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <param name=\"resultSelector\">A function to transform the final result.</param>\n        /// <returns>The filtered then aggregated then transformed sequence.</returns>\n        public static TResult FilterReduce<TSource, TAccumulate, TResult>(\n            this TSource[] source,\n            Func<TSource, bool> predicate,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func,\n            Func<TAccumulate, TResult> resultSelector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));\n\n            TAccumulate result = seed;\n            //int count = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    result = func(result, v);\n                    //count++;\n                }\n            }\n\n            return resultSelector(result);\n        }\n\n        // ----------------------------- Spans ------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static T FilterReduce<T>(this Span<T> source, Func<T, bool> predicate, Func<T, T, T> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            var result = default(T);\n\n            int i = 0;\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result = source[i];\n                    i++;\n                    break;\n                }\n            }\n\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result = func(result, source[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate with index for optimal performance\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence and it's index with.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static T FilterReduce<T>(this Span<T> source, Func<T, int, bool> predicate, Func<T, T, T> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = default(T);\n\n            int i = 0;\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result = source[i];\n                    i++;\n                    break;\n                }\n            }\n\n            for (; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result = func(result, source[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance with a starting seed.\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"seed\">The initial value to aggregate on.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static TAccumulate FilterReduce<TSource, TAccumulate>(\n            this Span<TSource> source,\n            Func<TSource, bool> predicate,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            TAccumulate result = seed;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                    result = func(result, v);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance with a starting seed and a result transformation.\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"seed\">The initial value to aggregate on.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <param name=\"resultSelector\">A function to transform the final result.</param>\n        /// <returns>The filtered then aggregated then transformed sequence.</returns>\n        public static TResult FilterReduce<TSource, TAccumulate, TResult>(\n            this Span<TSource> source,\n            Func<TSource, bool> predicate,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func,\n            Func<TAccumulate, TResult> resultSelector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));\n\n            TAccumulate result = seed;\n            //int count = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    result = func(result, v);\n                    //count++;\n                }\n            }\n\n            return resultSelector(result);\n        }\n#endif\n\n\n        // --------------------------- Lists -------------------------\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static T FilterReduce<T>(this List<T> source, Func<T, bool> predicate, Func<T, T, T> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            var result = default(T);\n\n            int i = 0;\n            for (; i < source.Count; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result = source[i];\n                    i++;\n                    break;\n                }\n            }\n\n            for (; i < source.Count; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result = func(result, source[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate with index for optimal performance\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence and it's index with.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static T FilterReduce<T>(this List<T> source, Func<T, int, bool> predicate, Func<T, T, T> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            var result = default(T);\n\n            int i = 0;\n            for (; i < source.Count; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result = source[i];\n                    i++;\n                    break;\n                }\n            }\n\n            for (; i < source.Count; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result = func(result, source[i]);\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance with a starting seed.\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"seed\">The initial value to aggregate on.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <returns>The filtered then aggregated sequence.</returns>\n        public static TAccumulate FilterReduce<TSource, TAccumulate>(\n            this List<TSource> source,\n            Func<TSource, bool> predicate,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            TAccumulate result = seed;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = source[i];\n                if (predicate(v))\n                    result = func(result, v);\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Combines Where and Aggregate for optimal performance with a starting seed and a result transformation.\n        /// </summary>        \n        /// <param name=\"source\">The input to filter then aggregate.</param>\n        /// <param name=\"predicate\">The function to filter the input sequence with.</param>\n        /// <param name=\"seed\">The initial value to aggregate on.</param>\n        /// <param name=\"func\">The function to aggregate the filtered sequence.</param>\n        /// <param name=\"resultSelector\">A function to transform the final result.</param>\n        /// <returns>The filtered then aggregated then transformed sequence.</returns>\n        public static TResult FilterReduce<TSource, TAccumulate, TResult>(\n            this List<TSource> source,\n            Func<TSource, bool> predicate,\n            TAccumulate seed,\n            Func<TAccumulate, TSource, TAccumulate> func,\n            Func<TAccumulate, TResult> resultSelector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (func == null) throw new ArgumentNullException(nameof(func));\n\n            if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));\n\n            TAccumulate result = seed;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var v = source[i];\n                if (predicate(v))\n                    result = func(result, v);\n            }\n\n            return resultSelector(result);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/WhereAggregate.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d9218245a4e42c14698c87b135829153\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/WhereSelect.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS --------------------------------------------\n\n\n        /// <summary>\n        /// Combined Where and Select for optimal performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter then transform.</param>\n        /// <param name=\"predicate\">A function to use to filter the sequence.</param>\n        /// <param name=\"selector\">A function to transform the filtered elements.</param>\n        /// <returns>A sequence of filtered and transformed elements.</returns>\n        public static TResult[] FilterMap<T, TResult>(this T[] source, Func<T, bool> predicate, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result[idx] = selector(source[i]);\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        /// <summary>\n        /// Combined Where and Select for optimal performance that uses the index in the \n        /// predicate and selector.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter then transform.</param>\n        /// <param name=\"predicate\">A function to use to filter the sequence.</param>\n        /// <param name=\"selector\">A function to transform the filtered elements.</param>\n        /// <returns>A sequence of filtered and transformed elements.</returns>\n        public static TResult[] FilterMap<T, TResult>(this T[] source, Func<T, int, bool> predicate, Func<T, int, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result[idx] = selector(source[i], idx);\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n\n        // --------------------------  SPANS --------------------------------------------\n\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Combined Where and Select for optimal performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter then transform.</param>\n        /// <param name=\"predicate\">A function to use to filter the sequence.</param>\n        /// <param name=\"selector\">A function to transform the filtered elements.</param>\n        /// <returns>A sequence of filtered and transformed elements.</returns>\n        public static TResult[] FilterMap<T, TResult>(this Span<T> source, Func<T, bool> predicate, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i]))\n                {\n                    result[idx] = selector(source[i]);\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n\n        /// <summary>\n        /// Combined Where and Select for optimal performance that uses the index in the \n        /// predicate and selector.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter then transform.</param>\n        /// <param name=\"predicate\">A function to use to filter the sequence.</param>\n        /// <param name=\"selector\">A function to transform the filtered elements.</param>\n        /// <returns>A sequence of filtered and transformed elements.</returns>\n        public static TResult[] FilterMap<T, TResult>(this Span<T> source, Func<T, int, bool> predicate, Func<T, int, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var result = new TResult[source.Length];\n            int idx = 0;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    result[idx] = selector(source[i], idx);\n                    idx++;\n                }\n            }\n\n            Array.Resize(ref result, idx);\n            return result;\n        }\n#endif\n\n\n        // --------------------------  LISTS --------------------------------------------\n\n        /// <summary>\n        /// Combined Where and Select for optimal performance.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter then transform.</param>\n        /// <param name=\"predicate\">A function to use to filter the sequence.</param>\n        /// <param name=\"selector\">A function to transform the filtered elements.</param>\n        /// <returns>A sequence of filtered and transformed elements.</returns>\n        public static List<TResult> FilterMap<T, TResult>(this List<T> source, Func<T, bool> predicate, Func<T, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new List<TResult>();\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i])) r.Add(selector(source[i]));\n            }\n\n            return r;\n        }\n\n        /// <summary>\n        /// Combined Where and Select for optimal performance that uses the index in the \n        /// predicate and selector.\n        /// </summary>        \n        /// <param name=\"source\">The input sequence to filter then transform.</param>\n        /// <param name=\"predicate\">A function to use to filter the sequence.</param>\n        /// <param name=\"selector\">A function to transform the filtered elements.</param>\n        /// <returns>A sequence of filtered and transformed elements.</returns>\n        public static List<TResult> FilterMap<T, TResult>(this List<T> source, Func<T, int, bool> predicate, Func<T, int, TResult> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (predicate == null) throw new ArgumentNullException(nameof(predicate));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            var r = new List<TResult>();\n            int idx = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                if (predicate(source[i], i))\n                {\n                    r.Add(selector(source[i], idx));\n                    idx++;\n                }\n            }\n\n\n            return r;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/WhereSelect.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 18a368bd1cc38d945a0010693a2f4913\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/WhereSum.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        // --------------------------  ARRAYS  --------------------------------------------\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static int FilterSum(this int[] source, Func<int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += v;\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static int FilterSum<T>(this T[] source, Func<T, bool> predicate, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += selector(v);\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static long FilterSum(this long[] source, Func<long, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += v;\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static long FilterSum<T>(this T[] source, Func<T, bool> predicate, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += selector(v);\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static float FilterSum(this float[] source, Func<float, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += v;\n                }\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>        \n        /// <returns>The sum of the transformed elements.</returns>\n        public static float FilterSum<T>(this T[] source, Func<T, bool> predicate, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static double FilterSum(this double[] source, Func<double, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static double FilterSum<T>(this T[] source, Func<T, bool> predicate, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static decimal FilterSum(this decimal[] source, Func<decimal, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            decimal sum = 0;\n\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static decimal FilterSum<T>(this T[] source, Func<T, bool> predicate, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        // --------------------------  SPANS  --------------------------------------------\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static int FilterSum(this Span<int> source, Func<int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += v;\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static int FilterSum<T>(this Span<T> source, Func<T, bool> predicate, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += selector(v);\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static long FilterSum(this Span<long> source, Func<long, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += v;\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static long FilterSum<T>(this Span<T> source, Func<T, bool> predicate, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                foreach (var v in source)\n                {\n                    if (predicate(v))\n                    {\n                        sum += selector(v);\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static float FilterSum(this Span<float> source, Func<float, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += v;\n                }\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>        \n        /// <returns>The sum of the transformed elements.</returns>\n        public static float FilterSum<T>(this Span<T> source, Func<T, bool> predicate, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static double FilterSum(this Span<double> source, Func<double, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static double FilterSum<T>(this Span<T> source, Func<T, bool> predicate, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static decimal FilterSum(this Span<decimal> source, Func<decimal, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            decimal sum = 0;\n\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += v;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static decimal FilterSum<T>(this Span<T> source, Func<T, bool> predicate, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal sum = 0;\n            foreach (var v in source)\n            {\n                if (predicate(v))\n                {\n                    sum += selector(v);\n                }\n            }\n\n            return sum;\n        }\n\n#endif\n        // --------------------------  LISTS  --------------------------------------------\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static int FilterSum(this List<int> source, Func<int, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            int sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    var s = source[i];\n                    if (predicate(s))\n                    {\n                        sum += s;\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static int FilterSum<T>(this List<T> source, Func<T, bool> predicate, Func<T, int> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            int sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    var s = source[i];\n                    if (predicate(s))\n                    {\n                        sum += selector(s);\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static long FilterSum(this List<long> source, Func<long, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    var s = source[i];\n                    if (predicate(s))\n                    {\n                        sum += s;\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static long FilterSum<T>(this List<T> source, Func<T, bool> predicate, Func<T, long> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            long sum = 0;\n            checked\n            {\n                for (int i = 0; i < source.Count; i++)\n                {\n                    var s = source[i];\n                    if (predicate(s))\n                    {\n                        sum += selector(s);\n                    }\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static float FilterSum(this List<float> source, Func<float, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = source[i];\n                if (predicate(s))\n                {\n                    sum += s;\n                }\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static float FilterSum<T>(this List<T> source, Func<T, bool> predicate, Func<T, float> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = source[i];\n                if (predicate(s))\n                {\n                    sum += selector(s);\n                }\n            }\n\n            return (float)sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static double FilterSum(this List<double> source, Func<double, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            double sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = source[i];\n                if (predicate(s))\n                {\n                    sum += s;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static double FilterSum<T>(this List<T> source, Func<T, bool> predicate, Func<T, double> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            double sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = source[i];\n                if (predicate(s))\n                {\n                    sum += selector(s);\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        ///  Adds the values in the sequence that match the where predicate.\n        /// </summary>\n        /// <param name=\"source\">The sequence to add.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <returns>The sum of the sequence.</returns>\n        public static decimal FilterSum(this List<decimal> source, Func<decimal, bool> predicate)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            decimal sum = 0;\n\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = source[i];\n                if (predicate(s))\n                {\n                    sum += s;\n                }\n            }\n\n            return sum;\n        }\n\n        /// <summary>\n        /// Performs a filter with the where predicate, then sums the transformed values.\n        /// </summary>        \n        /// <param name=\"source\">The sequence of values to transform then sum.</param>\n        /// <param name=\"predicate\">A function to filter the sequence with before summing.</param>\n        /// <param name=\"selector\">A transformation function.</param>\n        /// <returns>The sum of the transformed elements.</returns>\n        public static decimal FilterSum<T>(this List<T> source, Func<T, bool> predicate, Func<T, decimal> selector)\n        {\n            if (source == null) throw new ArgumentNullException(nameof(source));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            decimal sum = 0;\n            for (int i = 0; i < source.Count; i++)\n            {\n                var s = source[i];\n                if (predicate(s))\n                {\n                    sum += selector(s);\n                }\n            }\n\n            return sum;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/WhereSum.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 496c880709ba6b14db9943ce8ba50b3c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq/Zip.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace VirtueSky.Linq\n{\n    public static partial class L\n    {\n        /// <summary>\n        /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.\n        /// </summary>\n        /// <param name=\"first\">The first sequence to merge.</param>\n        /// <param name=\"second\">The second sequence to merge.</param>\n        /// <param name=\"selector\">A function that specifies how to merge the elements from the two sequences.</param>\n        /// <returns>A sequence that contains merged elements of two input sequences.</returns>\n        public static TR[] ZipF<T, TU, TR>(this T[] first, TU[] second, Func<T, TU, TR> selector)\n        {\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            //maintain array bounds elision\n            if (first.Length < second.Length)\n            {\n                var result = new TR[first.Length];\n                for (int i = 0; i < first.Length; i++)\n                {\n                    result[i] = selector(first[i], second[i]);\n                }\n\n                return result;\n            }\n            else\n            {\n                var result = new TR[second.Length];\n                for (int i = 0; i < second.Length; i++)\n                {\n                    result[i] = selector(first[i], second[i]);\n                }\n\n                return result;\n            }\n        }\n\n#if UNITY_2021_3_OR_NEWER\n        /// <summary>\n        /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.\n        /// </summary>\n        /// <param name=\"first\">The first sequence to merge.</param>\n        /// <param name=\"second\">The second sequence to merge.</param>\n        /// <param name=\"selector\">A function that specifies how to merge the elements from the two sequences.</param>\n        /// <returns>A sequence that contains merged elements of two input sequences.</returns>\n        public static TR[] ZipF<T, TU, TR>(this Span<T> first, Span<TU> second, Func<T, TU, TR> selector)\n        {\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            //maintain array bounds elision\n            if (first.Length < second.Length)\n            {\n                var result = new TR[first.Length];\n                for (int i = 0; i < first.Length; i++)\n                {\n                    result[i] = selector(first[i], second[i]);\n                }\n\n                return result;\n            }\n            else\n            {\n                var result = new TR[second.Length];\n                for (int i = 0; i < second.Length; i++)\n                {\n                    result[i] = selector(first[i], second[i]);\n                }\n\n                return result;\n            }\n        }\n#endif\n\n        /// <summary>\n        /// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.\n        /// </summary>\n        /// <param name=\"first\">The first sequence to merge.</param>\n        /// <param name=\"second\">The second sequence to merge.</param>\n        /// <param name=\"selector\">A function that specifies how to merge the elements from the two sequences.</param>\n        /// <returns>A sequence that contains merged elements of two input sequences.</returns>\n        public static List<TR> ZipF<T, TU, TR>(this List<T> first, List<TU> second, Func<T, TU, TR> selector)\n        {\n            if (first == null) throw new ArgumentNullException(nameof(first));\n\n            if (second == null) throw new ArgumentNullException(nameof(second));\n\n            if (selector == null) throw new ArgumentNullException(nameof(selector));\n\n            //maintain array bounds elision\n            if (first.Count < second.Count)\n            {\n                var result = new List<TR>(first.Count);\n                for (int i = 0; i < first.Count; i++)\n                {\n                    result.Add(selector(first[i], second[i]));\n                }\n\n                return result;\n            }\n            else\n            {\n                var result = new List<TR>(second.Count);\n                for (int i = 0; i < second.Count; i++)\n                {\n                    result.Add(selector(first[i], second[i]));\n                }\n\n                return result;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Linq/Zip.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c469cf6005aaf3246ac1a8251a93c4ce\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Linq.meta",
    "content": "fileFormatVersion: 2\nguid: 0aada19fe3bc91940be0410901475254\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Editor/AssetTreeViewItem.cs",
    "content": "using VirtueSky.Localization;\nusing UnityEditor.IMGUI.Controls;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    public class AssetTreeViewItem : TreeViewItem\n    {\n        private bool _isDirty;\n\n        /// <summary>\n        /// Gets or sets item as dirty. Added \"*\" postfix to the display name if is dirty.\n        /// </summary>\n        public bool IsDirty\n        {\n            get => _isDirty;\n            set\n            {\n                _isDirty = value;\n                if (value)\n                {\n                    displayName = Asset.name + \"*\";\n                }\n                else\n                {\n                    displayName = Asset.name;\n                }\n            }\n        }\n\n        public ScriptableLocaleBase Asset { get; private set; }\n\n        public AssetTreeViewItem(int depth, ScriptableLocaleBase data)\n            : base(data.GetInstanceID(), depth, data.name)\n        {\n            Asset = data;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/AssetTreeViewItem.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3161e46b9f8f4d3fab4bbe3958378a1a\ntimeCreated: 1700795837"
  },
  {
    "path": "VirtueSky/Localization/Editor/CsvSerialization.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    public class CsvSerialization\n    {\n        private const string KEY_COLUMN = \"Key\";\n\n        public void Serialize(Stream stream)\n        {\n            var languages = LocaleSettings.AvailableLanguages;\n            var localizedTexts = Locale.FindAllLocalizedAssets<LocaleText>();\n\n            using (var writer = new StreamWriter(stream))\n            {\n                // Write key column.\n                writer.Write(DoubleQuote(KEY_COLUMN));\n\n                if (languages.Count > 0) writer.Write(\",\");\n\n                // Write used language columns.\n                for (var i = 0; i < languages.Count; i++)\n                {\n                    writer.Write(DoubleQuote(\"{0} ({1})\"), languages[i].Code, languages[i].Name);\n\n                    if (i != languages.Count - 1) writer.Write(\",\");\n                }\n\n                writer.WriteLine();\n\n                // Write localized assets.\n                foreach (var localizedText in localizedTexts)\n                {\n                    // Write key.\n                    writer.Write(DoubleQuote(localizedText.name));\n\n                    if (languages.Count > 0) writer.Write(\",\");\n\n                    for (var i = 0; i < languages.Count; i++)\n                    {\n                        if (!localizedText.TryGetLocaleValue(languages[i], out string value)) value = \"\";\n\n                        writer.Write(DoubleQuote(value));\n\n                        if (i != languages.Count - 1) writer.Write(\",\");\n                    }\n\n                    writer.WriteLine();\n                }\n            }\n        }\n\n        public void Deserialize(Stream stream)\n        {\n            string importLocation = LocaleSettings.ImportLocation;\n            var localizedTexts = Locale.FindAllLocalizedAssets<LocaleText>();\n\n            using (var reader = new StreamReader(stream))\n            {\n                var languages = ReadImportLanguages(reader);\n\n                while (!reader.EndOfStream)\n                {\n                    string[] tokens = ReadNextTokens(reader);\n\n                    if (tokens.Length != languages.Count + 1) throw new IOException(\"Invalid row\");\n\n                    string key = tokens[0];\n                    if (string.IsNullOrEmpty(key)) throw new IOException(\"Key field must not be empty\");\n\n                    var localizedText = localizedTexts.FirstOrDefault(x => x.name == key);\n                    if (localizedText == null)\n                    {\n                        localizedText = ScriptableObject.CreateInstance<LocaleText>();\n\n                        string assetPath = Path.Combine(importLocation, $\"{key}.asset\");\n                        AssetDatabase.CreateAsset(localizedText, assetPath);\n                        AssetDatabase.SaveAssets();\n                    }\n\n                    // Read languages by ignoring first column (Key).\n                    for (var i = 1; i < tokens.Length; i++)\n                    {\n                        ScriptableLocaleEditor.AddOrUpdateLocale(localizedText, languages[i - 1], tokens[i]);\n                    }\n\n                    EditorUtility.SetDirty(localizedText);\n                }\n            }\n\n            AssetDatabase.Refresh();\n        }\n\n        private string[] ReadNextTokens(StreamReader reader)\n        {\n            var line = \"\";\n\n            do\n            {\n                if (line.Length != 0) line += \"\\n\";\n\n                line += reader.ReadLine();\n            } while (!reader.EndOfStream && line.Length > 0 && line[^1] != '\\\"');\n\n            if (line != null)\n            {\n                string[] tokens = Regex.Split(line, @\"\"\",\"\"\");\n                if (tokens.Length > 0)\n                {\n                    string token = tokens[0];\n\n                    if (token.Length > 0 && token[0] == '\\\"') token = token.Remove(0, 1);\n\n                    tokens[0] = token;\n                }\n\n                if (tokens.Length > 1)\n                {\n                    string token = tokens[^1];\n\n                    if (token.Length > 0 && token[^1] == '\\\"') token = token.Remove(token.Length - 1, 1);\n\n                    tokens[^1] = token;\n                }\n\n                return tokens;\n            }\n\n            return Array.Empty<string>();\n        }\n\n        private List<Language> ReadImportLanguages(StreamReader reader)\n        {\n            var availableLanguages = LocaleSettings.AllLanguages;\n            var importLanguages = new List<Language>();\n\n            string[] columnTokens = ReadNextTokens(reader);\n            if (columnTokens.Length == 0)\n            {\n                throw new IOException(\"Column size must be greater than zero\");\n            }\n\n            // Read languages by ignoring first column (Key).\n            for (var i = 1; i < columnTokens.Length; i++)\n            {\n                string token = columnTokens[i].Trim();\n                if (token.Length == 0) throw new IOException(\"Invalid language code column\");\n\n                // Read only language code.\n                // Emit language name if exist.\n                string[] tokens = token.Split(' ');\n                if (tokens.Length > 0) token = tokens[0].Trim();\n\n                var language = availableLanguages.FirstOrDefault(x => x.Code == token);\n                if (language == null)\n                {\n                    Debug.LogWarning(\"Language code (\" + token + \") not exist in localization system.\");\n                }\n\n                // Add null language as well to maintain order.\n                importLanguages.Add(language);\n            }\n\n            return importLanguages;\n        }\n\n        private static string DoubleQuote(string s)\n        {\n            return $\"\\\"{s}\\\"\";\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/CsvSerialization.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 899f85cc067e4f04e8e16cbffc6493ae\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Editor/EditorMenu.cs",
    "content": "using VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    public static class EditorMenu\n    {\n        private const string MENU_NAME = \"Sunflower/Localization/Change Locale/\";\n\n        [MenuItem(\"Sunflower/Localization/Import CSV\", priority = 10000)]\n        private static void ImportCsv()\n        {\n            LocaleEditorUtil.Import();\n        }\n\n        [MenuItem(\"Sunflower/Localization/Export CSV\", priority = 10001)]\n        private static void ExportCsv()\n        {\n            LocaleEditorUtil.Export();\n        }\n\n        private static void SetLanguage(Language currentLanguage)\n        {\n            if (!Application.isPlaying)\n            {\n                Debug.LogWarning(\"Setting language only available when application is playing.\");\n                return;\n            }\n\n            var previousLanguage = Locale.CurrentLanguage;\n            Locale.CurrentLanguage = currentLanguage;\n\n            Menu.SetChecked(GetMenuName(previousLanguage), false);\n            Menu.SetChecked(GetMenuName(currentLanguage), true);\n        }\n\n        [MenuItem(MENU_NAME + \"/Afrikaans\", priority = 10002)]\n        private static void ChangeToAfrikaans()\n        {\n            SetLanguage(Language.Afrikaans);\n        }\n\n        [MenuItem(MENU_NAME + \"/Arabic\", priority = 10003)]\n        private static void ChangeToArabic()\n        {\n            SetLanguage(Language.Arabic);\n        }\n\n        [MenuItem(MENU_NAME + \"/Basque\", priority = 10003)]\n        private static void ChangeToBasque()\n        {\n            SetLanguage(Language.Basque);\n        }\n\n        [MenuItem(MENU_NAME + \"/Belarusian\", priority = 10004)]\n        private static void ChangeToBelarusian()\n        {\n            SetLanguage(Language.Belarusian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Bulgarian\", priority = 10005)]\n        private static void ChangeToBulgarian()\n        {\n            SetLanguage(Language.Bulgarian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Catalan\", priority = 10006)]\n        private static void ChangeToCatalan()\n        {\n            SetLanguage(Language.Catalan);\n        }\n\n        [MenuItem(MENU_NAME + \"/Chinese\", priority = 10007)]\n        private static void ChangeToChinese()\n        {\n            SetLanguage(Language.Chinese);\n        }\n\n        [MenuItem(MENU_NAME + \"/Czech\", priority = 10008)]\n        private static void ChangeToCzech()\n        {\n            SetLanguage(Language.Czech);\n        }\n\n        [MenuItem(MENU_NAME + \"/Danish\", priority = 10009)]\n        private static void ChangeToDanish()\n        {\n            SetLanguage(Language.Danish);\n        }\n\n        [MenuItem(MENU_NAME + \"/Dutch\", priority = 10010)]\n        private static void ChangeToDutch()\n        {\n            SetLanguage(Language.Dutch);\n        }\n\n        [MenuItem(MENU_NAME + \"/English\", priority = 10011)]\n        private static void ChangeToEnglish()\n        {\n            SetLanguage(Language.English);\n        }\n\n        [MenuItem(MENU_NAME + \"/Estonian\", priority = 10012)]\n        private static void ChangeToEstonian()\n        {\n            SetLanguage(Language.Estonian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Faroese\", priority = 10013)]\n        private static void ChangeToFaroese()\n        {\n            SetLanguage(Language.Faroese);\n        }\n\n        [MenuItem(MENU_NAME + \"/Finnish\", priority = 10014)]\n        private static void ChangeToFinnish()\n        {\n            SetLanguage(Language.Finnish);\n        }\n\n        [MenuItem(MENU_NAME + \"/French\", priority = 10015)]\n        private static void ChangeToFrench()\n        {\n            SetLanguage(Language.French);\n        }\n\n        [MenuItem(MENU_NAME + \"/German\", priority = 10016)]\n        private static void ChangeToGerman()\n        {\n            SetLanguage(Language.German);\n        }\n\n        [MenuItem(MENU_NAME + \"/Greek\", priority = 10017)]\n        private static void ChangeToGreek()\n        {\n            SetLanguage(Language.Greek);\n        }\n\n        [MenuItem(MENU_NAME + \"/Hebrew\", priority = 10018)]\n        private static void ChangeToHebrew()\n        {\n            SetLanguage(Language.Hebrew);\n        }\n\n        [MenuItem(MENU_NAME + \"/Hungarian\", priority = 10019)]\n        private static void ChangeToHungarian()\n        {\n            SetLanguage(Language.Hungarian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Icelandic\", priority = 10020)]\n        private static void ChangeToIcelandic()\n        {\n            SetLanguage(Language.Icelandic);\n        }\n\n        [MenuItem(MENU_NAME + \"/Indonesian\", priority = 10021)]\n        private static void ChangeToIndonesian()\n        {\n            SetLanguage(Language.Indonesian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Italian\", priority = 10022)]\n        private static void ChangeToItalian()\n        {\n            SetLanguage(Language.Italian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Japanese\", priority = 10023)]\n        private static void ChangeToJapanese()\n        {\n            SetLanguage(Language.Japanese);\n        }\n\n        [MenuItem(MENU_NAME + \"/Korean\", priority = 10024)]\n        private static void ChangeToKorean()\n        {\n            SetLanguage(Language.Korean);\n        }\n\n        [MenuItem(MENU_NAME + \"/Latvian\", priority = 10025)]\n        private static void ChangeToLatvian()\n        {\n            SetLanguage(Language.Latvian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Lithuanian\", priority = 10026)]\n        private static void ChangeToLithuanian()\n        {\n            SetLanguage(Language.Lithuanian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Norwegian\", priority = 10027)]\n        private static void ChangeToNorwegian()\n        {\n            SetLanguage(Language.Norwegian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Polish\", priority = 10028)]\n        private static void ChangeToPolish()\n        {\n            SetLanguage(Language.Polish);\n        }\n\n        [MenuItem(MENU_NAME + \"/Portuguese\", priority = 10029)]\n        private static void ChangeToPortuguese()\n        {\n            SetLanguage(Language.Portuguese);\n        }\n\n        [MenuItem(MENU_NAME + \"/Romanian\", priority = 10030)]\n        private static void ChangeToRomanian()\n        {\n            SetLanguage(Language.Romanian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Russian\", priority = 10031)]\n        private static void ChangeToRussian()\n        {\n            SetLanguage(Language.Russian);\n        }\n\n        [MenuItem(MENU_NAME + \"/SerboCroatian\", priority = 10032)]\n        private static void ChangeToSerboCroatian()\n        {\n            SetLanguage(Language.SerboCroatian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Slovak\", priority = 10033)]\n        private static void ChangeToSlovak()\n        {\n            SetLanguage(Language.Slovak);\n        }\n\n        [MenuItem(MENU_NAME + \"/Slovenian\", priority = 10034)]\n        private static void ChangeToSlovenian()\n        {\n            SetLanguage(Language.Slovenian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Spanish\", priority = 10035)]\n        private static void ChangeToSpanish()\n        {\n            SetLanguage(Language.Spanish);\n        }\n\n        [MenuItem(MENU_NAME + \"/Swedish\", priority = 10036)]\n        private static void ChangeToSwedish()\n        {\n            SetLanguage(Language.Swedish);\n        }\n\n        [MenuItem(MENU_NAME + \"/Thai\", priority = 10037)]\n        private static void ChangeToThai()\n        {\n            SetLanguage(Language.Thai);\n        }\n\n        [MenuItem(MENU_NAME + \"/Turkish\", priority = 10038)]\n        private static void ChangeToTurkish()\n        {\n            SetLanguage(Language.Turkish);\n        }\n\n        [MenuItem(MENU_NAME + \"/Ukrainian\", priority = 10039)]\n        private static void ChangeToUkrainian()\n        {\n            SetLanguage(Language.Ukrainian);\n        }\n\n        [MenuItem(MENU_NAME + \"/Vietnamese\", priority = 10040)]\n        private static void ChangeToVietnamese()\n        {\n            SetLanguage(Language.Vietnamese);\n        }\n\n        private static string GetMenuName(Language language)\n        {\n            return $\"{MENU_NAME}{language}\";\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/EditorMenu.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0cb9834b9f274079a170e563944dcc6d\ntimeCreated: 1700818210"
  },
  {
    "path": "VirtueSky/Localization/Editor/LanguagePropertyDrawer.cs",
    "content": "using VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    [CustomPropertyDrawer(typeof(Language))]\n    public class LanguagePropertyDrawer : PropertyDrawer\n    {\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            LocaleEditorUtil.LanguageField(position, property, label);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/LanguagePropertyDrawer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 28602a5b2f3740e6a50673f383d2b162\ntimeCreated: 1701069715"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleEditorUtil.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    public static class LocaleEditorUtil\n    {\n        public static void LocaleDrawLanguageField(Rect position, ref LocaleTreeViewItem localeItem, bool showOnlyBuiltin = false)\n        {\n            var languages = new List<Language>();\n            languages.AddRange(Language.BuiltInLanguages);\n\n            if (!showOnlyBuiltin) languages.AddRange(GetCustomLanguages());\n\n            int currentValueIndex = -1;\n            for (int i = 0; i < languages.Count; i++)\n            {\n                if (languages[i].Code == localeItem.LocaleItem.Language.Code)\n                {\n                    currentValueIndex = i;\n                    break;\n                }\n            }\n\n            if (currentValueIndex < 0)\n            {\n                currentValueIndex = languages.FindIndex(x => x.Code == Language.English.Code);\n                Debug.Assert(currentValueIndex >= 0);\n            }\n\n            int newValueIndex = currentValueIndex;\n            if (GUI.Button(position, languages[currentValueIndex].Name, EditorStyles.popup))\n            {\n                var searchWindow = ExSearchWindow.Create(\"Choose Language\");\n\n                foreach (var lang in languages)\n                {\n                    var cache = lang;\n                    var item = localeItem;\n                    searchWindow.AddEntry(lang.Name,\n                        () =>\n                        {\n                            newValueIndex = languages.FindIndex(x => x.Code == cache.Code);\n\n                            if (newValueIndex != currentValueIndex) item.LocaleItem.Language = languages[newValueIndex];\n                        });\n                }\n\n                searchWindow.Open(position);\n            }\n        }\n\n        public static void LanguageField(Rect position, SerializedProperty property, GUIContent label, bool showOnlyBuiltin = false)\n        {\n            var languages = new List<Language>();\n            languages.AddRange(Language.BuiltInLanguages);\n\n            if (!showOnlyBuiltin) languages.AddRange(GetCustomLanguages());\n\n            EditorGUI.BeginProperty(position, label, property);\n\n            var languageName = property.FindPropertyRelative(\"name\");\n            var languageCode = property.FindPropertyRelative(\"code\");\n\n            int currentValueIndex = languages.FindIndex(x => x.Code == languageCode.stringValue);\n            if (currentValueIndex < 0)\n            {\n                currentValueIndex = languages.FindIndex(x => x == Language.English);\n                Debug.Assert(currentValueIndex >= 0);\n            }\n\n            if (GUI.Button(position, languages[currentValueIndex].Name, EditorStyles.popup))\n            {\n                var searchWindow = ExSearchWindow.Create(\"Choose Language\");\n                foreach (var lang in languages)\n                {\n                    var cache = lang;\n                    searchWindow.AddEntry(lang.Name,\n                        () =>\n                        {\n                            int newValue = languages.FindIndex(x => x.Code == cache.Code);\n                            if (newValue != currentValueIndex)\n                            {\n                                languageName.stringValue = languages[newValue].Name;\n                                languageCode.stringValue = languages[newValue].Code;\n                                property.serializedObject.ApplyModifiedProperties();\n                            }\n                        });\n                }\n\n                searchWindow.Open(position);\n            }\n\n            EditorGUI.EndProperty();\n        }\n\n        private static Language[] GetCustomLanguages()\n        {\n            if (LocaleSettings.Instance != null)\n            {\n                var customLanguages = LocaleSettings.AvailableLanguages.Where(x => x.Custom);\n                return customLanguages.ToArray();\n            }\n\n            return Array.Empty<Language>();\n        }\n\n        public static Language GetLanguageValueFromProperty(SerializedProperty languageProperty)\n        {\n            var nameProperty = languageProperty.FindPropertyRelative(\"name\");\n            if (nameProperty == null) throw new ArgumentException(\"Language.Name property could not be found\");\n\n            var codeProperty = languageProperty.FindPropertyRelative(\"code\");\n            if (codeProperty == null) throw new ArgumentException(\"Language.Code property could not be found\");\n\n            var customProperty = languageProperty.FindPropertyRelative(\"custom\");\n            if (customProperty == null) throw new ArgumentException(\"Language.Custom property could not be found\");\n\n            return new Language(nameProperty.stringValue, codeProperty.stringValue, customProperty.boolValue);\n        }\n\n        public static void SetLanguageProperty(SerializedProperty languageProperty, string name, string code, bool custom)\n        {\n            var nameProperty = languageProperty.FindPropertyRelative(\"name\");\n            if (nameProperty == null) throw new ArgumentException(\"Language.Name property could not be found\");\n\n            var codeProperty = languageProperty.FindPropertyRelative(\"code\");\n            if (codeProperty == null) throw new ArgumentException(\"Language.Code property could not be found\");\n\n            var customProperty = languageProperty.FindPropertyRelative(\"custom\");\n            if (customProperty == null) throw new ArgumentException(\"Language.Custom property could not be found\");\n\n            nameProperty.stringValue = name;\n            codeProperty.stringValue = code;\n            customProperty.boolValue = custom;\n        }\n\n        public static void SetLanguageProperty(SerializedProperty languageProperty, Language language)\n        {\n            SetLanguageProperty(languageProperty, language.Name, language.Code, language.Custom);\n        }\n\n        /// <summary>\n        /// Import CSV file\n        /// </summary>\n        public static void Import()\n        {\n            string path = EditorUtility.OpenFilePanel(\"Import CSV file\", \"\", \"csv\");\n            if (string.IsNullOrEmpty(path))\n            {\n                return;\n            }\n\n            try\n            {\n                using (var stream = File.OpenRead(path))\n                {\n                    var serialization = new CsvSerialization();\n                    serialization.Deserialize(stream);\n                }\n\n                Debug.Log(\"CSV file has been imported.\");\n            }\n            catch (Exception e)\n            {\n                Debug.LogError(e);\n            }\n        }\n\n        /// <summary>\n        /// Export CSV file\n        /// </summary>\n        public static void Export()\n        {\n            string fileName = Application.productName + \"-\" + DateTime.Now.ToString(\"dd-MM-yyyy\", CultureInfo.InvariantCulture);\n            string path = EditorUtility.SaveFilePanel(\"Export CSV file\", \"\", fileName, \"csv\");\n            if (string.IsNullOrEmpty(path))\n            {\n                return;\n            }\n\n            try\n            {\n                using (var stream = File.OpenWrite(path))\n                {\n                    var serialization = new CsvSerialization();\n                    serialization.Serialize(stream);\n                }\n\n                Debug.Log(\"CSV file has been exported to \" + path);\n            }\n            catch (Exception e)\n            {\n                Debug.LogError(e);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleEditorUtil.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ad507e22275a4b6e9cb15e8d1f64357f\ntimeCreated: 1700737003"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleSettingsEditor.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\n#if VIRTUESKY_BAKINGSHEET\nusing Google.Apis.Auth.OAuth2;\nusing Google.Apis.Drive.v3;\nusing Google.Apis.Services;\nusing Google.Apis.Sheets.v4;\n#endif\n\nusing VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    [CustomEditor(typeof(LocaleSettings), true)]\n    public class LocaleSettingsEditor : Editor\n    {\n        private ReorderableList _reorderableList;\n        private SerializedProperty _avaiableLanguageProperty;\n        private SerializedProperty _detectDeviceLanguageProperty;\n        private SerializedProperty _importLocationProperty;\n        private SerializedProperty _googleTranslateApiKeyProperty;\n        private SerializedProperty _spreadsheetKeyProperty;\n        private SerializedProperty _serviceAccountCredentialProperty;\n\n        private void Init()\n        {\n            _avaiableLanguageProperty ??= serializedObject.FindProperty(\"availableLanguages\");\n            _detectDeviceLanguageProperty ??= serializedObject.FindProperty(\"detectDeviceLanguage\");\n            _importLocationProperty ??= serializedObject.FindProperty(\"importLocation\");\n            _googleTranslateApiKeyProperty ??= serializedObject.FindProperty(\"googleTranslateApiKey\");\n            _spreadsheetKeyProperty ??= serializedObject.FindProperty(\"spreadsheetKey\");\n            _serviceAccountCredentialProperty ??= serializedObject.FindProperty(\"serviceAccountCredential\");\n\n            if (_avaiableLanguageProperty != null)\n            {\n                _reorderableList = new ReorderableList(serializedObject,\n                    _avaiableLanguageProperty,\n                    true,\n                    true,\n                    true,\n                    true) { drawHeaderCallback = OnDrawHeaderCallback, drawElementCallback = OnDrawElementCallback };\n\n                _reorderableList.onAddDropdownCallback += OnAddDropdownCallback;\n                _reorderableList.onRemoveCallback += OnRemoveCallback;\n                _reorderableList.onCanRemoveCallback += OnCanRemoveCallback;\n            }\n        }\n\n        private bool OnCanRemoveCallback(ReorderableList list)\n        {\n            return list.count > 1;\n        }\n\n        private void OnDrawElementCallback(Rect rect, int index, bool isactive, bool isfocused)\n        {\n            var languageProperty = _reorderableList.serializedProperty.GetArrayElementAtIndex(index);\n            var position = new Rect(rect.x, rect.y + 2, rect.width, EditorGUIUtility.singleLineHeight);\n\n            bool isCustom = languageProperty.FindPropertyRelative(\"custom\").boolValue;\n            if (isCustom)\n            {\n                var languageName = languageProperty.FindPropertyRelative(\"name\");\n                var languageCode = languageProperty.FindPropertyRelative(\"code\");\n\n                float labelWidth = EditorGUIUtility.labelWidth;\n\n                EditorGUIUtility.labelWidth = 40;\n                var r1 = new Rect(position.x, position.y, position.width / 2 - 2, position.height);\n                EditorGUI.PropertyField(r1, languageName, new GUIContent(languageName.displayName, \"Language name\"));\n\n                EditorGUIUtility.labelWidth = 40;\n                var r2 = new Rect(position.x + r1.width + 4, position.y, position.width / 2 - 2, position.height);\n                EditorGUI.PropertyField(r2, languageCode, new GUIContent(languageCode.displayName, \"ISO-639-1 code\"));\n\n                EditorGUIUtility.labelWidth = labelWidth;\n            }\n            else\n            {\n                LocaleEditorUtil.LanguageField(position, languageProperty, GUIContent.none, true);\n            }\n        }\n\n        private void OnDrawHeaderCallback(Rect rect)\n        {\n            EditorGUI.LabelField(rect, \"Available Languages\");\n        }\n\n        private void OnAddDropdownCallback(Rect buttonrect, ReorderableList list)\n        {\n            var menu = new GenericMenu();\n            menu.AddItem(new GUIContent(\"Language\", \"Adds built-in language.\"),\n                false,\n                () =>\n                {\n                    ReorderableList.defaultBehaviours.DoAddButton(list);\n\n                    var languageProperty = list.serializedProperty.GetArrayElementAtIndex(list.index);\n                    LocaleEditorUtil.SetLanguageProperty(languageProperty, Language.BuiltInLanguages[0]);\n\n                    serializedObject.ApplyModifiedProperties();\n                });\n            menu.AddItem(new GUIContent(\"Custom language\", \"Adds custom language.\"),\n                false,\n                () =>\n                {\n                    ReorderableList.defaultBehaviours.DoAddButton(list);\n\n                    var languageProperty = list.serializedProperty.GetArrayElementAtIndex(list.index);\n                    LocaleEditorUtil.SetLanguageProperty(languageProperty, \"\", \"\", true);\n\n                    serializedObject.ApplyModifiedProperties();\n                });\n            menu.AddItem(new GUIContent(\"Adds languages in-use\", \"Adds by searching used languages in assets.\"),\n                false,\n                () =>\n                {\n                    AddUsedLocales();\n                    serializedObject.ApplyModifiedProperties();\n                });\n            menu.ShowAsContext();\n        }\n\n        private void OnRemoveCallback(ReorderableList list)\n        {\n            var languageProperty = list.serializedProperty.GetArrayElementAtIndex(list.index);\n            var language = LocaleEditorUtil.GetLanguageValueFromProperty(languageProperty);\n            if (language.Custom)\n            {\n                var localizedAssets = Locale.FindAllLocalizedAssets();\n                if (localizedAssets.Any(x => x.LocaleItems.Any(y => y.Language == language)))\n                {\n                    if (!EditorUtility.DisplayDialog(\"Remove \\\"\" + language + \"\\\" language?\",\n                            \"\\\"\" + language + \"\\\" language is in-use by some localized assets.\" +\n                            \" Are you sure to remove?\",\n                            \"Remove\",\n                            \"Cancel\"))\n                    {\n                        return; // Cancelled.\n                    }\n                }\n            }\n\n            ReorderableList.defaultBehaviours.DoRemoveButton(list);\n        }\n\n        private void AddUsedLocales()\n        {\n            var languages = FindUsedLanguages();\n            _avaiableLanguageProperty.arraySize = languages.Length;\n            for (var i = 0; i < _avaiableLanguageProperty.arraySize; i++)\n            {\n                var languageProperty = _avaiableLanguageProperty.GetArrayElementAtIndex(i);\n                LocaleEditorUtil.SetLanguageProperty(languageProperty, languages[i]);\n            }\n        }\n\n        private Language[] FindUsedLanguages()\n        {\n            var languages = new HashSet<Language>();\n            for (var i = 0; i < _avaiableLanguageProperty.arraySize; i++)\n            {\n                languages.Add(\n                    LocaleEditorUtil.GetLanguageValueFromProperty(_avaiableLanguageProperty.GetArrayElementAtIndex(i)));\n            }\n\n            var localizedAssets = Locale.FindAllLocalizedAssets();\n            foreach (var localizedAsset in localizedAssets)\n            {\n                foreach (var locale in localizedAsset.LocaleItems)\n                {\n                    languages.Add(locale.Language);\n                }\n            }\n\n            return languages.ToArray();\n        }\n\n        public override void OnInspectorGUI()\n        {\n            Init();\n\n            if (_reorderableList != null)\n            {\n                serializedObject.Update();\n\n                EditorGUILayout.Separator();\n\n                _reorderableList.DoLayoutList();\n\n                EditorGUILayout.PropertyField(_detectDeviceLanguageProperty, true);\n                EditorGUILayout.Separator();\n                EditorGUILayout.BeginHorizontal();\n                EditorGUILayout.PrefixLabel(_importLocationProperty.displayName);\n                if (GUILayout.Button(_importLocationProperty.stringValue, EditorStyles.objectField))\n                {\n                    string path = EditorUtility.OpenFolderPanel(\"Select folder for import location\", \"Assets/\", \"\");\n                    if (Directory.Exists(path))\n                    {\n                        path = \"Assets\" + path.Replace(Application.dataPath, \"\");\n                        if (AssetDatabase.IsValidFolder(path))\n                        {\n                            _importLocationProperty.stringValue = path;\n                        }\n                    }\n                }\n\n                EditorGUILayout.EndHorizontal();\n\n                EditorGUILayout.Separator();\n                EditorGUILayout.PropertyField(_googleTranslateApiKeyProperty);\n                if (string.IsNullOrEmpty(_googleTranslateApiKeyProperty.stringValue))\n                {\n                    EditorGUILayout.HelpBox(\n                        \"If you want to use Google Translate in editor or in-game, attach the API key file claimed from Google Cloud.\",\n                        MessageType.Info);\n                }\n                else\n                {\n                    if (_googleTranslateApiKeyProperty.stringValue.StartsWith(\"AIzaSyCdaIrr\") &&\n                        _googleTranslateApiKeyProperty.stringValue.EndsWith(\"120Dy-mfz6I\"))\n                        EditorGUILayout.HelpBox(\"Do not use this key. Replace with your API key\", MessageType.Info);\n                }\n\n                EditorGUILayout.Separator();\n#if VIRTUESKY_BAKINGSHEET\n                EditorGUILayout.BeginHorizontal();\n                EditorGUILayout.PropertyField(_spreadsheetKeyProperty);\n                if (GUILayout.Button(\"Open\", GUILayout.Width(65)))\n                {\n                    Application.OpenURL(\n                        $\"https://docs.google.com/spreadsheets/d/{_spreadsheetKeyProperty.stringValue}\");\n                }\n\n                GUI.backgroundColor = Uniform.Green;\n                GUI.enabled = !EditorApplication.isCompiling && !SessionState.GetBool(\"spreasheet_importing\", false);\n                if (GUILayout.Button(\"Import\", GUILayout.Width(65)))\n                {\n                    if (EditorUtility.DisplayDialog(\"Import Locale From Spreasheet\",\n                            \"Are you sure you wish import Locale from Spreasheet?\\nThis action cannot be reversed.\",\n                            \"Ok\",\n                            \"Cancel\"))\n                    {\n                        ImportFormSpreadsheet();\n                    }\n                }\n\n                GUI.enabled = true;\n                GUI.backgroundColor = Color.white;\n                EditorGUILayout.EndHorizontal();\n#else\n                EditorGUILayout.HelpBox(\n                    $\"Add scripting define symbols: {ConstantDefineSymbols.VIRTUESKY_BAKINGSHEET} and install sdk to use spread sheet\",\n                    MessageType.Info);\n#endif\n\n                EditorGUILayout.PropertyField(_serviceAccountCredentialProperty, GUILayout.MaxHeight(150));\n                serializedObject.ApplyModifiedProperties();\n            }\n            else\n            {\n                base.OnInspectorGUI();\n            }\n        }\n\n        private async void ImportFormSpreadsheet()\n        {\n            SessionState.SetBool(\"spreasheet_importing\", true);\n            string importLocation = LocaleSettings.ImportLocation;\n            var localizedTexts = Locale.FindAllLocalizedAssets<LocaleText>();\n#if VIRTUESKY_BAKINGSHEET\n                    using (var service = new SheetsService(new BaseClientService.Initializer\n                   {\n                       HttpClientInitializer = GoogleCredential.FromJson(_serviceAccountCredentialProperty.stringValue)\n                           .CreateScoped(DriveService.Scope.DriveReadonly)\n                   }))\n            {\n                var sheetReq = service.Spreadsheets.Get(_spreadsheetKeyProperty.stringValue);\n                sheetReq.Fields = \"properties,sheets(properties,data.rowData.values.formattedValue)\";\n                var spreadsheet = await sheetReq.ExecuteAsync();\n\n                var languages = new List<Language>();\n                var availableLanguages = LocaleSettings.AllLanguages;\n                foreach (var s in spreadsheet.Sheets)\n                {\n                    if (!s.Properties.Title.Equals(Application.productName)) continue;\n                    foreach (var g in s.Data)\n                    {\n                        for (var i = 1; i < g.RowData[0].Values.Count; i++)\n                        {\n                            string code = g.RowData[0].Values[i].FormattedValue;\n                            var language = availableLanguages.FirstOrDefault(x => x.Code == code);\n                            if (language == null)\n                                Debug.LogWarning(\"Language code (\" + code + \") not exist in localization system.\");\n\n                            // Add null language as well to maintain order.\n                            languages.Add(language);\n                        }\n\n                        for (var i = 1; i < g.RowData.Count; i++)\n                        {\n                            var row = g.RowData[i].Values;\n                            var key = row[0];\n                            var localizedText = localizedTexts.FirstOrDefault(x => x.name == key.FormattedValue);\n                            if (localizedText == null)\n                            {\n                                localizedText = CreateInstance<LocaleText>();\n\n                                string assetPath = Path.Combine(importLocation, $\"{key}.asset\");\n                                AssetDatabase.CreateAsset(localizedText, assetPath);\n                                AssetDatabase.SaveAssets();\n                            }\n\n                            // Read languages by ignoring first column (Key).\n                            for (var j = 1; j < row.Count; j++)\n                            {\n                                ScriptableLocaleEditor.AddOrUpdateLocale(localizedText, languages[j - 1],\n                                    row[j].FormattedValue);\n                            }\n\n                            EditorUtility.SetDirty(localizedText);\n                        }\n                    }\n                }\n\n                AssetDatabase.Refresh();\n            }\n\n            Debug.Log(\"[Localization] The import process from spreasheet is complete\");\n            SessionState.SetBool(\"spreasheet_importing\", false);\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleSettingsEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 67bab48307e34de69ccc4f5778ee8aaa\ntimeCreated: 1700734943"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleTreeView.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing VirtueSky.Localization;\nusing TMPro;\nusing UnityEditor;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEngine;\nusing UnityEngine.Assertions;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    public class LocaleTreeView : TreeView\n    {\n        private enum ColumnType\n        {\n            Type,\n            Name,\n            Language,\n            Value\n        }\n\n        private int _id;\n        private float _valueFieldWidth;\n        private GUIStyle _textAreaStyle;\n        private Rect _cellRect;\n\n        public LocaleTreeView(TreeViewState state)\n            : base(state)\n        {\n        }\n\n        public LocaleTreeView(TreeViewState state, MultiColumnHeader multiColumnHeader)\n            : base(state, multiColumnHeader)\n        {\n            _textAreaStyle = new GUIStyle(EditorStyles.textArea) { wordWrap = true };\n            rowHeight = 20;\n            columnIndexForTreeFoldouts = 1;\n            showAlternatingRowBackgrounds = true;\n            showBorder = true;\n\n            customFoldoutYOffset = (20 - EditorGUIUtility.singleLineHeight) * 0.5f;\n            multiColumnHeader.canSort = false;\n            Reload();\n        }\n\n        protected override TreeViewItem BuildRoot()\n        {\n            _id = 1;\n            var root = new TreeViewItem { id = 0, depth = -1, displayName = \"Root\" };\n            var localizedAssets = Locale.FindAllLocalizedAssets();\n            var allItems = new List<TreeViewItem>();\n\n            // Add localized assets.\n            foreach (var localizedAsset in localizedAssets)\n            {\n                var assetItem = new AssetTreeViewItem(0, localizedAsset);\n                allItems.Add(assetItem);\n\n                // Add locale items.\n                var localItems = localizedAsset.LocaleItems;\n                for (var i = 0; i < localItems.Length; i++)\n                {\n                    allItems.Add(new LocaleTreeViewItem(_id++, 1, localItems[i], assetItem));\n                }\n            }\n\n            // Utility method that initializes the TreeViewItem.children and .parent for all items.\n            SetupParentsAndChildrenFromDepths(root, allItems);\n            return root;\n        }\n\n        protected override void RowGUI(RowGUIArgs args)\n        {\n            for (int i = 0; i < args.GetNumVisibleColumns(); ++i)\n            {\n                var columnType = (ColumnType)args.GetColumn(i);\n                var cellRect = args.GetCellRect(i);\n                CellGUI(cellRect, args.item, columnType, ref args);\n\n                // Refresh row heights if the Value column width is changed.\n                if (columnType == ColumnType.Value && cellRect.width != _valueFieldWidth)\n                {\n                    _valueFieldWidth = cellRect.width;\n                    RefreshCustomRowHeights();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Make TextArea as expandable as possible.\n        /// </summary>\n        protected override float GetCustomRowHeight(int row, TreeViewItem item)\n        {\n            float h = base.GetCustomRowHeight(row, item);\n            if (item is LocaleTreeViewItem localeItem)\n            {\n                var assetItem = localeItem.Parent;\n                if (assetItem.Asset.GetGenericType == typeof(string))\n                {\n                    var column = multiColumnHeader.GetColumn(3);\n                    if (column != null)\n                    {\n                        var stringValue = (string)localeItem.LocaleItem.ObjectValue;\n                        float calculatedRowHeight = _textAreaStyle.CalcHeight(new GUIContent(stringValue), column.width) + 4;\n                        h = Mathf.Clamp(calculatedRowHeight, h, 100);\n                    }\n                }\n            }\n\n            return h;\n        }\n\n        void CellGUI(Rect cellRect, TreeViewItem item, ColumnType column, ref RowGUIArgs args)\n        {\n            switch (column)\n            {\n                case ColumnType.Type:\n                    DrawTypeCell(cellRect, item);\n                    break;\n                case ColumnType.Name:\n                    DrawNameCell(cellRect, item, ref args);\n                    break;\n                case ColumnType.Language:\n                    DrawLanguageCell(cellRect, item);\n                    break;\n                case ColumnType.Value:\n                    DrawValueCell(cellRect, item);\n                    break;\n            }\n        }\n\n        private void DrawTypeCell(Rect cellRect, TreeViewItem item)\n        {\n            CenterRectUsingSingleLineHeight(ref cellRect);\n            var treeViewItem = item as AssetTreeViewItem;\n            if (treeViewItem != null)\n            {\n                Texture icon;\n\n                // Set icon by localized asset value type.\n                var valueType = treeViewItem.Asset.GetGenericType;\n                if (valueType == typeof(string))\n                {\n                    icon = EditorGUIUtility.ObjectContent(null, typeof(TextAsset)).image;\n                }\n                else if (valueType == typeof(TMP_FontAsset))\n                {\n                    icon = EditorGUIUtility.ObjectContent(null, typeof(Font)).image;\n                }\n                else\n                {\n                    icon = EditorGUIUtility.ObjectContent(null, valueType).image;\n                }\n\n                // Set default icon if not exist.\n                if (!icon)\n                {\n                    icon = EditorGUIUtility.ObjectContent(null, typeof(ScriptableObject)).image;\n                }\n\n                if (icon)\n                {\n                    GUI.DrawTexture(cellRect, icon, ScaleMode.ScaleToFit);\n                }\n            }\n        }\n\n        private void DrawNameCell(Rect cellRect, TreeViewItem item, ref RowGUIArgs args)\n        {\n            ValidateMissingLocales(item);\n\n            CenterRectUsingSingleLineHeight(ref cellRect);\n            args.rowRect = cellRect;\n            base.RowGUI(args);\n            GUI.contentColor = Color.white;\n        }\n\n        private void ValidateMissingLocales(TreeViewItem item)\n        {\n            var assetTreeViewItem = item as AssetTreeViewItem;\n            var assetItem = assetTreeViewItem?.Asset;\n            var localizedText = assetItem as LocaleText;\n            if (localizedText == null) return;\n            foreach (var typedLocaleItem in localizedText.TypedLocaleItems)\n            {\n                GUI.contentColor = string.IsNullOrEmpty(typedLocaleItem.Value) ? new Color(0.97f, 0.33f, 0.41f) : Color.white;\n            }\n        }\n\n\n        private void DrawLanguageCell(Rect cellRect, TreeViewItem item)\n        {\n            cellRect.y += 2;\n            cellRect.height -= 4;\n            if (item is LocaleTreeViewItem localeItem)\n            {\n                LocaleEditorUtil.LocaleDrawLanguageField(cellRect, ref localeItem);\n            }\n        }\n\n        private void DrawValueCell(Rect cellRect, TreeViewItem item)\n        {\n            cellRect.y += 2;\n            cellRect.height -= 4;\n            if (item is LocaleTreeViewItem treeViewItem)\n            {\n                var localeItem = treeViewItem.LocaleItem;\n                var valueType = treeViewItem.Parent.Asset.GetGenericType;\n\n                EditorGUI.BeginChangeCheck();\n                if (valueType.IsSubclassOf(typeof(UnityEngine.Object)))\n                {\n                    if (valueType == typeof(TMP_FontAsset) && localeItem.ObjectValue == null)\n                    {\n                        localeItem.ObjectValue = EditorGUI.ObjectField(cellRect, null, typeof(TMP_FontAsset), false);\n                    }\n                    else\n                    {\n                        localeItem.ObjectValue = EditorGUI.ObjectField(cellRect, (UnityEngine.Object)localeItem.ObjectValue, localeItem.ObjectValue.GetType(), false);\n                    }\n                }\n                else if (valueType == typeof(string))\n                {\n                    EditorGUI.BeginChangeCheck();\n                    localeItem.ObjectValue = EditorGUI.TextArea(cellRect, (string)localeItem.ObjectValue, _textAreaStyle);\n                    if (EditorGUI.EndChangeCheck())\n                    {\n                        RefreshCustomRowHeights();\n                    }\n                }\n                else\n                {\n                    EditorGUI.LabelField(cellRect, valueType + \" value type not supported.\");\n                }\n\n                if (EditorGUI.EndChangeCheck())\n                {\n                    treeViewItem.Parent.IsDirty = true;\n                    EditorUtility.SetDirty(treeViewItem.Parent.Asset);\n                }\n            }\n        }\n\n        protected override bool CanRename(TreeViewItem item)\n        {\n            if (item is AssetTreeViewItem)\n            {\n                // Only allow rename if we can show the rename overlay with a certain width (label might be clipped\n                // by other columns).\n                var renameRect = GetRenameRect(treeViewRect, 0, item);\n                return renameRect.width > 30;\n            }\n\n            return false;\n        }\n\n        protected override void RenameEnded(RenameEndedArgs args)\n        {\n            // Set the backend name and reload the tree to reflect the new model\n            if (args.acceptedRename)\n            {\n                var item = FindItem(args.itemID, rootItem) as AssetTreeViewItem;\n                if (item != null)\n                {\n                    string assetPath = AssetDatabase.GetAssetPath(item.Asset.GetInstanceID());\n                    AssetDatabase.RenameAsset(assetPath, args.newName);\n                    AssetDatabase.SaveAssets();\n                    Reload();\n                }\n            }\n        }\n\n        public TreeViewItem GetSelectedItem()\n        {\n            var selection = GetSelection();\n            if (selection.Count > 0)\n            {\n                return FindItem(selection[0], rootItem);\n            }\n\n            return null;\n        }\n\n        protected override Rect GetRenameRect(Rect rowRect, int row, TreeViewItem item)\n        {\n            var cellRect = GetCellRectForTreeFoldouts(rowRect);\n            CenterRectUsingSingleLineHeight(ref cellRect);\n            return base.GetRenameRect(cellRect, row, item);\n        }\n\n        public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState(float treeViewWidth)\n        {\n            var typeColumnWidth = 30;\n            var nameColumnWidth = 150;\n            var languageColumnWidth = 110;\n            float valueColumnWidth = treeViewWidth - typeColumnWidth - nameColumnWidth - languageColumnWidth;\n            var columns = new[]\n            {\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(EditorGUIUtility.FindTexture(\"FilterByType\"), \"Localized asset type.\"),\n                    contextMenuText = \"Type\",\n                    headerTextAlignment = TextAlignment.Center,\n                    sortedAscending = true,\n                    sortingArrowAlignment = TextAlignment.Center,\n                    width = typeColumnWidth,\n                    minWidth = 30,\n                    maxWidth = 60,\n                    autoResize = false,\n                    allowToggleVisibility = true\n                },\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(\"Name\", \"Localized asset name.\"),\n                    headerTextAlignment = TextAlignment.Left,\n                    sortedAscending = true,\n                    sortingArrowAlignment = TextAlignment.Center,\n                    width = nameColumnWidth,\n                    minWidth = 60,\n                    autoResize = false,\n                    allowToggleVisibility = false\n                },\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(\"Language\", \"Locale language.\"),\n                    headerTextAlignment = TextAlignment.Left,\n                    sortedAscending = true,\n                    sortingArrowAlignment = TextAlignment.Center,\n                    width = languageColumnWidth,\n                    minWidth = 35,\n                    autoResize = false\n                },\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(\"Value\", \"Locale value.\"),\n                    headerTextAlignment = TextAlignment.Left,\n                    sortedAscending = true,\n                    sortingArrowAlignment = TextAlignment.Left,\n                    width = valueColumnWidth,\n                    minWidth = 60,\n                    autoResize = true\n                }\n            };\n\n            Assert.AreEqual(columns.Length,\n                Enum.GetValues(typeof(ColumnType)).Length,\n                \"Number of columns should match number of enum values: You probably forgot to update one of them.\");\n\n            var state = new MultiColumnHeaderState(columns);\n            return state;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleTreeView.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2bbde9ae865d43eaa3854f73a514867e\ntimeCreated: 1700794399"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleTreeViewItem.cs",
    "content": "using VirtueSky.Localization;\nusing UnityEditor.IMGUI.Controls;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    public class LocaleTreeViewItem : TreeViewItem\n    {\n        public LocaleItemBase LocaleItem { get; private set; }\n        public AssetTreeViewItem Parent { get; private set; }\n\n        public LocaleTreeViewItem(int id, int depth, LocaleItemBase localeItem, AssetTreeViewItem parent)\n            : base(id, depth, \"\")\n        {\n            LocaleItem = localeItem;\n            Parent = parent;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/LocaleTreeViewItem.cs.meta",
    "content": "fileFormatVersion: 2\nguid: acf3a9988b6142fba133610d1a86eafa\ntimeCreated: 1700795969"
  },
  {
    "path": "VirtueSky/Localization/Editor/PostBuildProcessor.cs",
    "content": "using System.Collections.Generic;\nusing VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEditor.Callbacks;\n\n#if UNITY_IOS\nusing System.IO;\nusing UnityEngine;\nusing UnityEditor.iOS.Xcode;\n#endif\n\nnamespace MyNamespace\n{\n    public static class PostBuildProcessor\n    {\n        [PostProcessBuild(9999)]\n        public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject)\n        {\n#if UNITY_IOS\n            if (buildTarget == BuildTarget.iOS)\n            {\n                // Continue if any localization info exists.\n                var localizations = GetLocalizations();\n                if (localizations.Count == 0)\n                {\n                    return;\n                }\n\n                // Get plist.\n                var plistPath = pathToBuiltProject + \"/Info.plist\";\n                var plist = new PlistDocument();\n                plist.ReadFromString(File.ReadAllText(plistPath));\n\n                // Get root of plist/dict.\n                var rootDict = plist.root;\n                var plistLocalizations = rootDict.CreateArray(\"CFBundleLocalizations\");\n\n                // Add localizations.\n                foreach (string locale in localizations)\n                {\n                    plistLocalizations.AddString(locale);\n                    Debug.Log(\"[LocalizationBuildPostprocessor] Localization added: \" + locale);\n                }\n\n                // Save all changes.\n                File.WriteAllText(plistPath, plist.WriteToString());\n            }\n#endif\n        }\n\n        private static List<string> GetLocalizations()\n        {\n            var localizations = new List<string>();\n            if (LocaleSettings.Instance != null)\n            {\n                foreach (var language in LocaleSettings.AvailableLanguages)\n                {\n                    localizations.Add(language.Code);\n                }\n            }\n\n            return localizations;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/PostBuildProcessor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b0d039b7f39e03b4ba3653ae712de662\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Editor/ScriptableLocaleEditor.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing VirtueSky.Localization;\nusing UnityEditor;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing VirtueSky.Misc;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.LocalizationEditor\n{\n    [CustomEditor(typeof(ScriptableLocaleBase), true)]\n    [CanEditMultipleObjects]\n    public class ScriptableLocaleEditor : UnityEditor.Editor\n    {\n        private static GoogleTranslator Translator => new(LocaleSettings.GoogleTranslateApiKey);\n        private ReorderableList _reorderable;\n        private SerializedProperty _itemsProperty;\n        private Rect _currentLayoutRect;\n        private GUIStyle _textAreaStyle;\n\n        private GUIStyle TextAreaStyle\n        {\n            get { return _textAreaStyle ??= new GUIStyle(EditorStyles.textArea) { wordWrap = true }; }\n        }\n\n        private void OnEnable()\n        {\n            if (target == null) return;\n            var assetValueType = ((ScriptableLocaleBase)target).GetGenericType;\n            _itemsProperty = serializedObject.FindProperty(\"items\");\n            if (_itemsProperty != null)\n            {\n                _reorderable = new ReorderableList(serializedObject: serializedObject,\n                    elements: _itemsProperty,\n                    draggable: true,\n                    displayHeader: true,\n                    displayAddButton: true,\n                    displayRemoveButton: true)\n                {\n                    drawHeaderCallback = rect => { EditorGUI.LabelField(rect, ObjectNames.NicifyVariableName(target.GetType().Name) + \"s\"); }\n                };\n\n                _reorderable.drawElementCallback = (rect, index, _, _) =>\n                {\n                    var element = _reorderable.serializedProperty.GetArrayElementAtIndex(index);\n\n                    // Language field.\n                    var languageRect = new Rect(rect.x, rect.y + 2, 100, rect.height - 4);\n                    var languageProperty = element.FindPropertyRelative(\"language\");\n                    EditorGUI.PropertyField(languageRect, languageProperty, GUIContent.none);\n\n                    // Value field.\n                    var valueRect = new Rect(languageRect.x + languageRect.width + 4, languageRect.y, rect.width - languageRect.width - 4, rect.height - 4);\n                    var valueProperty = element.FindPropertyRelative(\"value\");\n                    if (assetValueType == typeof(string))\n                    {\n                        valueProperty.stringValue = EditorGUI.TextArea(valueRect, valueProperty.stringValue, TextAreaStyle);\n                    }\n                    else\n                    {\n                        EditorGUI.PropertyField(valueRect, valueProperty, GUIContent.none);\n                    }\n                };\n                _reorderable.onCanRemoveCallback = list => list.count > 1;\n                _reorderable.elementHeightCallback = index =>\n                {\n                    var element = _reorderable.serializedProperty.GetArrayElementAtIndex(index);\n                    var valueProperty = element.FindPropertyRelative(\"value\");\n                    float elementHeight = EditorGUIUtility.singleLineHeight;\n\n                    if (assetValueType == typeof(string))\n                    {\n                        float valueWidth = _currentLayoutRect.width - 100 - 30;\n                        elementHeight = TextAreaStyle.CalcHeight(new GUIContent(valueProperty.stringValue), valueWidth);\n                    }\n\n                    return Mathf.Max(EditorGUIUtility.singleLineHeight, elementHeight) + 4;\n                };\n                _reorderable.onAddDropdownCallback = (_, list) =>\n                {\n                    var menu = new GenericMenu();\n                    menu.AddItem(new GUIContent(\"Language\", \"Adds a language.\"),\n                        false,\n                        () =>\n                        {\n                            ReorderableList.defaultBehaviours.DoAddButton(list);\n                            serializedObject.ApplyModifiedProperties();\n                        });\n                    menu.AddItem(new GUIContent(\"Add languages from settings\", \"Adds by searching used languages in assets.\"),\n                        false,\n                        () =>\n                        {\n                            AddLanguagesFromSettings();\n                            serializedObject.ApplyModifiedProperties();\n                        });\n                    menu.AddItem(new GUIContent(\"Add all languages\", \"Adds all languages.\"),\n                        false,\n                        () =>\n                        {\n                            AddAllLanguages();\n                            serializedObject.ApplyModifiedProperties();\n                        });\n                    menu.ShowAsContext();\n                };\n            }\n        }\n\n        public override void OnInspectorGUI()\n        {\n            if (Selection.objects.Length > 1)\n            {\n                EditorGUILayout.HelpBox(\"Currently does not support editing multiple Locales at the same time. Just choose one\", MessageType.Warning);\n                return;\n            }\n\n            if (_reorderable != null)\n            {\n                _currentLayoutRect = GUILayoutUtility.GetRect(0, _reorderable.GetHeight(), GUILayout.ExpandWidth(true));\n                serializedObject.Update();\n                _reorderable.DoList(_currentLayoutRect);\n                serializedObject.ApplyModifiedProperties();\n\n                Rect helpRect;\n                if (target is LocaleText localeText)\n                {\n                    if (GUILayout.Button(\"Translate\"))\n                    {\n                        Debug.Log(\"[Localization] Starting Translate LocaleText: \".SetColor(Color.cyan) + localeText.name);\n                        var firstLocale = localeText.TypedLocaleItems.First();\n                        foreach (var locale in localeText.TypedLocaleItems)\n                        {\n                            if (!string.IsNullOrEmpty(locale.Value)) continue;\n\n                            var localeItem = locale;\n                            Translator.Translate(new GoogleTranslateRequest(firstLocale.Language, locale.Language, firstLocale.Value),\n                                e =>\n                                {\n                                    var response = e.Responses.FirstOrDefault();\n                                    if (response != null)\n                                    {\n                                        localeItem.Value = response.translatedText;\n                                        Debug.Log(\"[Localization] Translate Successfull: \".SetColor(CustomColor.Green) + localeText.name);\n                                    }\n\n                                    EditorUtility.SetDirty(localeText);\n                                },\n                                e => { Debug.LogError(\"Response (\" + e.ResponseCode + \"): \" + e.Message); });\n                        }\n                    }\n\n                    if (GUILayout.Button(\"Fill Language Same Avaiable Language\"))\n                    {\n                        Debug.Log(\"[Localization] Starting fill language same with AvaiableLanguage for LocaleText!\".SetColor(Color.cyan));\n\n                        foreach (var item in localeText.LocaleItems.ToList())\n                        {\n                            var result = localeText.LocaleItems.Select(itemBase => new LocaleItem<string>(itemBase.Language, itemBase.ObjectValue.ToString())).ToList();\n\n                            // remove duplicate\n                            for (var i = 0; i < result.ToList().Count - 1; i++)\n                            {\n                                var cache = result[i];\n                                for (var j = 0; j < result.ToList().Count; j++)\n                                {\n                                    if (j == i) continue;\n                                    if (result[j].Language == cache.Language) result.RemoveAt(j);\n                                }\n                            }\n\n                            int index = Array.FindIndex(localeText.LocaleItems, x => x.Language == item.Language);\n                            if (!LocaleSettings.AvailableLanguages.Contains(localeText.LocaleItems[index].Language)) result.RemoveAt(index);\n\n                            localeText.SetLocaleItems(result);\n                        }\n\n                        if (localeText.LocaleItems.Length < LocaleSettings.AvailableLanguages.Count)\n                        {\n                            foreach (var lang in LocaleSettings.AvailableLanguages)\n                            {\n                                int index = Array.FindIndex(localeText.LocaleItems, x => x.Language == lang);\n                                if (index >= 0) continue;\n\n                                AddLocale(localeText);\n                                index = localeText.LocaleItems.Length - 1;\n                                var localeItem = localeText.LocaleItems[index];\n                                localeItem.Language = lang;\n                                localeItem.ObjectValue = \"\";\n                            }\n                        }\n\n                        Debug.Log(\"[Localization] Fill language same with AvaiableLanguage Successfull: \".SetColor(CustomColor.Green) + localeText.name);\n                    }\n\n                    helpRect = _currentLayoutRect;\n                    helpRect.y += _reorderable.GetHeight() + 50;\n                }\n                else\n                {\n                    helpRect = _currentLayoutRect;\n                    helpRect.y += _reorderable.GetHeight() + 4;\n                }\n\n                helpRect.height = EditorGUIUtility.singleLineHeight * 1.5f;\n                EditorGUI.HelpBox(helpRect, \"First locale item is used as fallback if needed.\", MessageType.Info);\n            }\n            else\n            {\n                base.OnInspectorGUI();\n\n                EditorGUILayout.HelpBox(\"Make sure that locale items variable name is declared as \\\"m_LocaleItems\\\" and it is serializable.\", MessageType.Error);\n            }\n        }\n\n        private void AddAllLanguages()\n        {\n            AddLanguages(LocaleSettings.AllLanguages);\n        }\n\n        private void AddLanguagesFromSettings()\n        {\n            AddLanguages(LocaleSettings.AvailableLanguages);\n        }\n\n        private void AddLanguages(List<Language> languages)\n        {\n            var filteredLanguages = languages.Where(x => !IsLanguageExist(_itemsProperty, x)).ToArray();\n\n            int startIndex = _itemsProperty.arraySize;\n            _itemsProperty.arraySize += filteredLanguages.Length;\n\n            for (var i = 0; i < filteredLanguages.Length; i++)\n            {\n                var localeItem = _itemsProperty.GetArrayElementAtIndex(startIndex + i);\n\n                var localeItemValue = localeItem.FindPropertyRelative(\"value\");\n                switch (localeItemValue.propertyType)\n                {\n                    case SerializedPropertyType.String:\n                        localeItemValue.stringValue = \"\";\n                        break;\n                    default:\n                        localeItemValue.objectReferenceValue = null;\n                        break;\n                }\n\n                var localeItemLanguage = localeItem.FindPropertyRelative(\"language\");\n                LocaleEditorUtil.SetLanguageProperty(localeItemLanguage, filteredLanguages[i]);\n            }\n        }\n\n        private static bool IsLanguageExist(SerializedProperty localeItemsProperty, Language language)\n        {\n            for (var i = 0; i < localeItemsProperty.arraySize; i++)\n            {\n                var element = localeItemsProperty.GetArrayElementAtIndex(i);\n                var languageProperty = element.FindPropertyRelative(\"language\");\n                string languageCode = languageProperty.FindPropertyRelative(\"code\").stringValue;\n                if (languageCode == language.Code)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Adds a locale and the value or updates if specified language is existing.\n        /// </summary>\n        public static bool AddOrUpdateLocale(ScriptableLocaleBase localizedAsset, Language language, object value)\n        {\n            var serializedObject = new SerializedObject(localizedAsset);\n            serializedObject.Update();\n\n            var elements = serializedObject.FindProperty(\"items\");\n            if (elements != null && elements.arraySize > 0)\n            {\n                int index = Array.FindIndex(localizedAsset.LocaleItems, x => x.Language == language);\n                if (index < 0)\n                {\n                    AddLocale(localizedAsset);\n                    index = localizedAsset.LocaleItems.Length - 1;\n                }\n\n                var localeItem = localizedAsset.LocaleItems[index];\n                localeItem.Language = language;\n                localeItem.ObjectValue = value;\n                return true;\n            }\n\n            return false;\n        }\n\n\n        /// <summary>\n        /// Adds a locale end of the list by copying last one.\n        /// </summary>\n        public static bool AddLocale(ScriptableLocaleBase localizedAsset)\n        {\n            var serializedObject = new SerializedObject(localizedAsset);\n            serializedObject.Update();\n\n            var elements = serializedObject.FindProperty(\"items\");\n            if (elements != null)\n            {\n                elements.arraySize += 1;\n                serializedObject.ApplyModifiedProperties();\n                return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Removes specified locale item from the list.\n        /// </summary>\n        public static bool RemoveLocale(ScriptableLocaleBase localizedAsset, LocaleItemBase localeItem)\n        {\n            var serializedObject = new SerializedObject(localizedAsset);\n            serializedObject.Update();\n\n            var elements = serializedObject.FindProperty(\"items\");\n            if (elements != null && elements.arraySize > 1)\n            {\n                int index = Array.IndexOf(localizedAsset.LocaleItems, localeItem);\n                if (index >= 0)\n                {\n                    elements.DeleteArrayElementAtIndex(index);\n                    serializedObject.ApplyModifiedProperties();\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/ScriptableLocaleEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fbf069e56fe04065a9688fb9db098b35\ntimeCreated: 1700811314"
  },
  {
    "path": "VirtueSky/Localization/Editor/VirtueSky.Sunflower.Localization.Editor.asmdef",
    "content": "{\n    \"name\": \"VirtueSky.Sunflower.Localization.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c7e7793e0b5d326429f90e6fd716775e\",\n        \"GUID:6055be8ebefd69e48b49212b09b47b2f\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Localization/Editor/VirtueSky.Sunflower.Localization.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 6a3996cca4c689e4597a79d47ef54353\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 4541ab8d10d0ffd4fa21bf4fa05cd76f\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleAudioClipComponent.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleAudioClipComponent : LocaleComponentGeneric<LocaleAudioClip, AudioClip>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleAudioClipComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2e7fb96ec2704d6990df46c485ffc81f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponent.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    [ExecuteInEditMode]\n    public abstract class LocaleComponent : MonoBehaviour\n    {\n        private bool _isOnValidate;\n        public event EventHandler<EventArgs> LocaleChangedEvent;\n\n        protected virtual void OnEnable()\n        {\n            ForceUpdate();\n            if (Application.isPlaying) Locale.LocaleChangedEvent += LocaleChangedInvoke;\n        }\n\n        private void LocaleChangedInvoke(object sender, LocaleChangedEventArgs e)\n        {\n            ForceUpdate();\n        }\n\n        public void ForceUpdate()\n        {\n            if (TryUpdateComponentLocalization(_isOnValidate)) OnLocaleChangedEvent();\n\n            _isOnValidate = false;\n        }\n\n        protected virtual void OnDisable()\n        {\n            if (Application.isPlaying) Locale.LocaleChangedEvent -= LocaleChangedInvoke;\n        }\n\n        protected virtual void OnLocaleChangedEvent()\n        {\n            LocaleChangedEvent?.Invoke(this, EventArgs.Empty);\n        }\n\n        /// <summary>\n        /// Gets the localized value safely.\n        /// </summary>\n        protected static T GetValueOrDefault<T>(LocaleVariable<T> variable) where T : class\n        {\n            return variable ? variable.Value : default;\n        }\n\n        private void OnValidate()\n        {\n            _isOnValidate = true;\n            ForceUpdate();\n        }\n\n        /// <summary>\n        /// Updates component localization if possible.\n        /// </summary>\n        /// <remarks>\n        /// Use <see cref=\"ForceUpdate\"/> to update component localization.\n        /// Use this method to override only.\n        /// </remarks>\n        /// <param name=\"isOnValidate\">This method is whether called by <see cref=\"OnValidate\"/> or not.</param>\n        /// <returns>True if component is updated successfully.</returns>\n        protected abstract bool TryUpdateComponentLocalization(bool isOnValidate);\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 00e8bb0211d8487caaa2330848fa1a30\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGeneric.cs",
    "content": "﻿using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    public class LocaleComponentGeneric<TVariable, T> : LocaleComponentGenericBase where TVariable : LocaleVariable<T> where T : class\n    {\n        [SerializeField] private TVariable variable;\n\n        public TVariable Variable\n        {\n            get => variable;\n            set\n            {\n                variable = value;\n                ForceUpdate();\n            }\n        }\n\n        protected override Type GetValueType() => typeof(T);\n\n        protected override bool HasLocaleValue() => Variable != null;\n        protected override object GetLocaleValue() => GetValueOrDefault(variable);\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGeneric.cs.meta",
    "content": "fileFormatVersion: 2\nguid: df7e6a70081d4ba48f8e4eb4eef89afc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGenericBase.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    public abstract class LocaleComponentGenericBase : LocaleComponent\n    {\n        [SerializeField] private Component component;\n        [SerializeField] private Optional<string> property;\n\n        private PropertyInfo _propertyInfo;\n\n        private void Awake()\n        {\n            Init();\n        }\n\n        private void Init()\n        {\n            if (_propertyInfo == null) TryInitProperty();\n        }\n\n        private bool TryInitProperty()\n        {\n            if (component != null)\n            {\n                _propertyInfo = FindProperty(component, property.Value);\n                return _propertyInfo != null;\n            }\n\n            return false;\n        }\n\n        public bool TrySetComponentAndProperty<TComponent>(string propertyName) where TComponent : Component\n        {\n            component = GetComponent<TComponent>();\n            if (component != null)\n            {\n                property = new Optional<string>(false, propertyName);\n\n                if (!TryInitProperty())\n                {\n                    property = new Optional<string>(false, \"\");\n                    return false;\n                }\n\n                return true;\n            }\n\n            return false;\n        }\n\n        public bool TrySetComponentAndPropertyIfNotSet<TComponent>(string propertyName)\n            where TComponent : Component\n        {\n            return component == null && TrySetComponentAndProperty<TComponent>(propertyName);\n        }\n\n        private PropertyInfo FindProperty(Component c, string propertyName)\n        {\n            return c.GetType().GetProperty(propertyName, GetValueType());\n        }\n\n        /// <summary>\n        /// Finds list of localizable properties of specified component.\n        /// </summary>\n        internal List<PropertyInfo> FindProperties(Component component)\n        {\n            var valueType = GetValueType();\n            var allProperties = component.GetType().GetProperties();\n            var properties = new List<PropertyInfo>();\n            foreach (var p in allProperties)\n            {\n                if (p.CanWrite && valueType.IsAssignableFrom(p.PropertyType)) properties.Add(p);\n            }\n\n            return properties;\n        }\n\n        protected abstract Type GetValueType();\n        protected abstract bool HasLocaleValue();\n        protected abstract object GetLocaleValue();\n\n        protected override bool TryUpdateComponentLocalization(bool isOnValidate)\n        {\n#if UNITY_EDITOR\n            if (!Application.isPlaying) Init();\n#endif\n\n            if (HasLocaleValue() && _propertyInfo != null)\n            {\n#if UNITY_EDITOR\n                if (!Application.isPlaying) UnityEditor.Undo.RecordObject(component, \"locale value changed\");\n#endif\n                _propertyInfo.SetValue(component, GetLocaleValue(), null);\n                return true;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleComponentGenericBase.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c3fd2a3b62114eadaa77be8418bd622c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleFontComponent.cs",
    "content": "﻿using TMPro;\nusing UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleFontComponent : LocaleComponentGeneric<LocaleFont, Font>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<Text>(\"font\");\n            TrySetComponentAndPropertyIfNotSet<TextMesh>(\"font\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleFontComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 039bf27d4d5c4d589f834b515f5df93b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleMaterialComponent.cs",
    "content": "using TMPro;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    using UnityEngine;\n\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleMaterialComponent : LocaleComponentGeneric<LocaleMaterial, Material>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<Renderer>(\"material\");\n            TrySetComponentAndPropertyIfNotSet<TMP_Text>(\"fontMaterial\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleMaterialComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a2e17a0a9298b014daac3f73685bfd04\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocalePrefabComponent.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocalePrefabComponent : LocaleComponent\n    {\n        public LocalePrefab prefab;\n        private GameObject _instance;\n\n        protected override bool TryUpdateComponentLocalization(bool isOnValidate)\n        {\n#if UNITY_EDITOR\n            if (Application.isPlaying && !isOnValidate)\n            {\n#endif\n                if (prefab)\n                {\n                    if (_instance) Destroy(_instance);\n                    _instance = Instantiate(prefab.Value, transform);\n                    return true;\n                }\n\n#if UNITY_EDITOR\n            }\n#endif\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocalePrefabComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 948b7b1689814a1f9e6825ee1e7b42b8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleRendererComponent.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleRendererComponent : LocaleComponent\n    {\n        public int materialIndex;\n        public string propertyName = \"_MainTex\";\n        public LocaleTexture localeTexture;\n\n        protected override bool TryUpdateComponentLocalization(bool isOnValidate)\n        {\n            if (localeTexture)\n            {\n                var materials = GetMaterials();\n                if (materialIndex < materials.Length)\n                {\n                    materials[materialIndex].SetTexture(propertyName, GetValueOrDefault(localeTexture));\n                    return true;\n                }\n\n                Debug.LogWarning(\"Index out of range : \" + materialIndex.ToString());\n            }\n\n\n            return false;\n        }\n\n        private void OnValidate()\n        {\n            materialIndex = materialIndex.Max(0);\n        }\n\n        private Material[] GetMaterials()\n        {\n#if UNITY_EDITOR\n            if (Application.isPlaying) return GetComponent<Renderer>().sharedMaterials;\n#endif\n            return GetComponent<Renderer>().materials;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleRendererComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6ada74822b484d4295211203588c0d95\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSharedMaterialComponent.cs",
    "content": "using TMPro;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    using UnityEngine;\n\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleSharedMaterialComponent : LocaleComponentGeneric<LocaleMaterial, Material>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<Renderer>(\"sharedMaterial\");\n            TrySetComponentAndPropertyIfNotSet<TMP_Text>(\"fontSharedMaterial\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSharedMaterialComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d76ad44851a25a74a918e5ec8039616c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSpriteComponent.cs",
    "content": "﻿using UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleSpriteComponent : LocaleComponentGeneric<LocaleSprite, Sprite>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<Image>(\"sprite\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleSpriteComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9b94f319fd1343a1abd8936aef0ef5fa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTMPFontComponent.cs",
    "content": "using TMPro;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleTMPFontComponent : LocaleComponentGeneric<LocaleTMPFont, TMP_FontAsset>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<TextMeshProUGUI>(\"font\");\n            TrySetComponentAndPropertyIfNotSet<TextMeshPro>(\"font\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTMPFontComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 476932f1680198544b423513d634d37e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextAssetComponent.cs",
    "content": "﻿using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleTextAssetComponent : LocaleComponentGeneric<LocaleTextAsset, TextAsset>\n    {\n        protected override Type GetValueType() => typeof(string);\n\n        protected override object GetLocaleValue() => Variable ? Variable.Value.text : null;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextAssetComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e728a8082a404697b9c9003c68403e78\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextComponent.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing TMPro;\nusing UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleTextComponent : LocaleComponentGeneric<LocaleText, string>\n    {\n        [SerializeField] private string[] formatArgs = Array.Empty<string>();\n\n        public string[] FormatArgs\n        {\n            get => formatArgs;\n            set\n            {\n                formatArgs = value ?? Array.Empty<string>();\n                ForceUpdate();\n            }\n        }\n\n        public void UpdateArgs(params string[] args)\n        {\n            FormatArgs = args;\n        }\n\n        protected override object GetLocaleValue()\n        {\n            var value = (string)base.GetLocaleValue();\n            if (FormatArgs.Length > 0 && !string.IsNullOrEmpty(value))\n            {\n                return string.Format(value, FormatArgs.Cast<object>().ToArray());\n            }\n\n            return value;\n        }\n\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<Text>(\"text\");\n            TrySetComponentAndPropertyIfNotSet<TextMeshProUGUI>(\"text\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e6c43f4ebada4d6ab7202113210604cb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextCompositeComponent.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing TMPro;\nusing UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleTextCompositeComponent : LocaleComponentGenericBase\n    {\n        [SerializeField] private string seperate = \", \";\n        [SerializeField] private LocaleText[] variables;\n        [SerializeField] private string[] formatArgs = Array.Empty<string>();\n\n        public string[] FormatArgs\n        {\n            get => formatArgs;\n            set\n            {\n                formatArgs = value ?? Array.Empty<string>();\n                ForceUpdate();\n            }\n        }\n\n        public LocaleText[] Variables\n        {\n            get => variables;\n            set\n            {\n                variables = value;\n                ForceUpdate();\n            }\n        }\n\n        public void UpdateArgs(params string[] args)\n        {\n            FormatArgs = args;\n        }\n\n        public void UpdateVariables(params LocaleText[] args)\n        {\n            Variables = args;\n        }\n\n        protected override Type GetValueType() => typeof(string);\n\n        protected override bool HasLocaleValue() => variables is { Length: > 0 };\n\n        protected override object GetLocaleValue()\n        {\n            (string value, int totalArgs) = CompositeString(seperate);\n            if (FormatArgs.Length >= totalArgs && !string.IsNullOrEmpty(value))\n            {\n                return string.Format(value, FormatArgs.Cast<object>().ToArray());\n            }\n\n            return value;\n        }\n\n        private (string, int) CompositeString(string seperate = \", \")\n        {\n            var index = 0;\n            var result = string.Empty;\n            var stringBuilder = new StringBuilder();\n            foreach (var text in variables)\n            {\n                string temp = GetValueOrDefault(text);\n                const string pattern = @\"{(.*?)}\";\n                int count = Regex.Matches(temp, pattern).OfType<Match>().Select(m => m.Value).Distinct().Count();\n                int j = count - 1 + index;\n                for (int i = count - 1; i >= 0; i--)\n                {\n                    stringBuilder.Clear();\n                    stringBuilder.Append(\"{\");\n                    stringBuilder.Append(i);\n                    var old = stringBuilder.ToString();\n                    stringBuilder.Clear();\n                    stringBuilder.Append(\"{\");\n                    stringBuilder.Append(j);\n                    temp = temp.Replace(old, stringBuilder.ToString());\n                    index++;\n                    j--;\n                }\n\n                stringBuilder.Clear();\n                if (!string.IsNullOrEmpty(result))\n                {\n                    stringBuilder.Append(result);\n                    stringBuilder.Append(seperate);\n                }\n\n                stringBuilder.Append(temp);\n                result = stringBuilder.ToString();\n            }\n\n            return (result, index);\n        }\n\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<Text>(\"text\");\n            TrySetComponentAndPropertyIfNotSet<TextMeshProUGUI>(\"text\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextCompositeComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 70f72d8f5ec175e4f9f6dff221346f2b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureComponent.cs",
    "content": "using UnityEngine;\nusing UnityEngine.UI;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleTextureComponent : LocaleComponentGeneric<LocaleTexture, Texture>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<RawImage>(\"texture\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 379fc5901f104995931aeee4aed7bf03\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureMaterialComponent.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleTextureMaterialComponent : LocaleComponent\n    {\n        public Material material;\n        public string propertyName = \"_MainTex\";\n        public LocaleTexture localeTexture;\n\n        protected override bool TryUpdateComponentLocalization(bool isOnValidate)\n        {\n            if (material != null && localeTexture != null)\n            {\n                material.SetTexture(propertyName, GetValueOrDefault(localeTexture));\n                return true;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleTextureMaterialComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cdb3c045afde41f2b8e4185820cb0fba\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleVideoClipComponent.cs",
    "content": "﻿using UnityEngine.Video;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_csharp\")]\n    public class LocaleVideoClipComponent : LocaleComponentGeneric<LocaleVideoClip, VideoClip>\n    {\n        private void Reset()\n        {\n            TrySetComponentAndPropertyIfNotSet<VideoPlayer>(\"video\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour/LocaleVideoClipComponent.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5f529b9d4c944447b01155db88a9110e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: f865308f7c963a749b9072d9efcd9bbf, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Behaviour.meta",
    "content": "fileFormatVersion: 2\nguid: 09335eee0c50433a9540e0834dc033e1\ntimeCreated: 1700728805"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Event/ScriptableEventLocaleText.cs",
    "content": "using VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    using UnityEngine;\n\n    [CreateAssetMenu(fileName = \"event_localetext.asset\", menuName = \"Sunflower/Localization/Events/locale text\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class ScriptableEventLocaleText : BaseEvent<LocaleText>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Event/ScriptableEventLocaleText.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0818b2a65300c6e4e9a33fe916a194c0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Event.meta",
    "content": "fileFormatVersion: 2\nguid: 13cc2fa7ae5daac4bbd5726c0c69486d\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleAudioClip.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/AudioClip\", fileName = \"audioclip_localizevalue\", order = 7)]\n    [EditorIcon(\"scriptable_yellow_audioclip\")]\n    public class LocaleAudioClip : LocaleVariable<AudioClip>\n    {\n        [Serializable]\n        private class AudioClipLocaleItem : LocaleItem<AudioClip>\n        {\n        };\n\n        [SerializeField] private AudioClipLocaleItem[] items = new AudioClipLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleAudioClip.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b083367c44e04827abfa540062a41c21\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 2579f1f676b7f2843a4cafaf429f9474, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleFont.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/Font\", fileName = \"font_localizevalue\", order = 1)]\n    [EditorIcon(\"scriptable_yellow_font\")]\n    public class LocaleFont : LocaleVariable<Font>\n    {\n        [Serializable]\n        private class FontLocaleItem : LocaleItem<Font>\n        {\n        };\n\n        [SerializeField] private FontLocaleItem[] items = new FontLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleFont.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 759309c703f44e55a8b2e699057b6670\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 6612c7be3408486478603096058345a2, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleMaterial.cs",
    "content": "using System;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    using UnityEngine;\n\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/Material\", fileName = \"material_localizevalue\", order = 1)]\n    [EditorIcon(\"scriptable_yellow_material\")]\n    public class LocaleMaterial : LocaleVariable<Material>\n    {\n        [Serializable]\n        private class MaterialLocaleItem : LocaleItem<Material>\n        {\n        };\n\n        [SerializeField] private MaterialLocaleItem[] items = new MaterialLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleMaterial.cs.meta",
    "content": "fileFormatVersion: 2\nguid: acdfe7459f01ac840b0d9cf370ab27ab\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 0bf47bf639988dc499e672dd3d0b7c26, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocalePrefab.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/GameObject\", fileName = \"gameobject_localizevalue\", order = 2)]\n    [EditorIcon(\"scriptable_yellow_gameobject\")]\n    public class LocalePrefab : LocaleVariable<GameObject>\n    {\n        [Serializable]\n        private class PrefabLocaleItem : LocaleItem<GameObject>\n        {\n        };\n\n        [SerializeField] private PrefabLocaleItem[] items = new PrefabLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocalePrefab.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0196d594670d4bf787f969202971648d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: bfd31c3e578dee04295c2133a97be5dd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleSprite.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/Sprite\", fileName = \"sprite_localizevalue\", order = 3)]\n    [EditorIcon(\"scriptable_yellow_sprite\")]\n    public class LocaleSprite : LocaleVariable<Sprite>\n    {\n        [Serializable]\n        private class SpriteLocaleItem : LocaleItem<Sprite>\n        {\n        };\n\n        [SerializeField] private SpriteLocaleItem[] items = new SpriteLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items.ToArray<LocaleItemBase>();\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleSprite.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3481dbc1ff9b4f4eac1a0eae04e50bf4\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: b2b3b70f4d3c0884faa424282862c6ca, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleTMPFont.cs",
    "content": "using System;\nusing TMPro;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/TMPFont\", fileName = \"font_asset_localizevalue\", order = 1)]\n    [EditorIcon(\"scriptable_yellow_fontasset\")]\n    public class LocaleTMPFont : LocaleVariable<TMP_FontAsset>\n    {\n        [Serializable]\n        private class TMPFontLocaleItem : LocaleItem<TMP_FontAsset>\n        {\n        };\n\n        [SerializeField] private TMPFontLocaleItem[] items = new TMPFontLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleTMPFont.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2400eef271b142798c5180db7f2084e6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 120a98534767efd4ba0b7a9e91cda393, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleText.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Linq;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/Text\", fileName = \"text_localizevalue\", order = 4)]\n    [EditorIcon(\"scriptable_yellow_text\")]\n    [Serializable]\n    public class LocaleText : LocaleVariable<string>\n    {\n        [Serializable]\n        private class TextLocaleItem : LocaleItem<string>\n        {\n        };\n\n        [SerializeField] private TextLocaleItem[] items = new TextLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n\n        /// <summary>\n        /// Sets locale items in Editor or Playmode.\n        /// </summary>\n        public void SetLocaleItems(List<LocaleItem<string>> items)\n        {\n            if (items == null) throw new ArgumentNullException(nameof(items));\n\n            this.items = items.Map(i => new TextLocaleItem { Language = i.Language, Value = i.Value }).ToArray();\n        }\n\n        /// <summary>\n        /// Sets locale items in Editor or Playmode.\n        /// </summary>\n        public void SetLocaleItems(LocaleItem<string>[] items)\n        {\n            if (items == null) throw new ArgumentException(nameof(items));\n\n            this.items = items.Map(i => new TextLocaleItem { Language = i.Language, Value = i.Value }).ToArray();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleText.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 23c351e45916415fa870992171e2731d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 13605300fcfb1fd45b49212af32ba2f8, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleTextAsset.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/TextAsset\", fileName = \"textasset_localizevalue\", order = 5)]\n    [EditorIcon(\"scriptable_yellow_textasset\")]\n    public class LocaleTextAsset : LocaleVariable<TextAsset>\n    {\n        [Serializable]\n        private class TextAssetLocaleItem : LocaleItem<TextAsset>\n        {\n        };\n\n        [SerializeField] private TextAssetLocaleItem[] items = new TextAssetLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleTextAsset.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7929c07a091e42b9bc29fb15a91900ae\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5b605beec23f2f6408ce4cae4dedd075, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleTexture.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/Texture\", fileName = \"texture_localizevalue\", order = 6)]\n    [EditorIcon(\"scriptable_yellow_texture\")]\n    public class LocaleTexture : LocaleVariable<Texture>\n    {\n        [Serializable]\n        private class TextureLocaleItem : LocaleItem<Texture>\n        {\n        };\n\n        [SerializeField] private TextureLocaleItem[] items = new TextureLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleTexture.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c12f7ea24b48413fa8c5e43f78cf029a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: a7f0847a6f95e2e46a76f375e4c2d001, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleVariable.cs",
    "content": "using System;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public abstract class LocaleVariable<T> : ScriptableLocaleBase where T : class\n    {\n        /// <summary>\n        /// Gets the defined locale items of the localized asset with concrete type.\n        /// </summary>\n        public LocaleItem<T>[] TypedLocaleItems => (LocaleItem<T>[])LocaleItems;\n\n        /// <summary>\n        /// Gets localized asset value regarding to <see cref=\"Locale.CurrentLanguage\"/> if available.\n        /// Gets first value of the asset if application is not playing.\n        /// </summary>\n        /// <seealso cref=\"Application.isPlaying\"/>\n        public T Value\n        {\n            get\n            {\n                var value = default(T);\n                var isValueSet = false;\n#if UNITY_EDITOR\n                if (Application.isPlaying)\n                {\n#endif\n                    isValueSet = TryGetLocaleValue(Locale.CurrentLanguage, out value);\n#if UNITY_EDITOR\n                }\n                else\n                {\n                    // Get default language from settings if is not in Play mode.\n                    if (LocaleSettings.AvailableLanguages.Any())\n                    {\n                        isValueSet = TryGetLocaleValue(LocaleSettings.AvailableLanguages.First(), out value);\n                    }\n                }\n#endif\n\n                return isValueSet ? value : FirstValue;\n            }\n        }\n\n        /// <summary>\n        /// Gets the first locale value of the asset.\n        /// </summary>\n        public T FirstValue\n        {\n            get\n            {\n                var localeItem = TypedLocaleItems.FirstOrDefault();\n                return localeItem?.Value;\n            }\n        }\n\n        /// <summary>\n        /// Returns the language given is whether exist or not.\n        /// </summary>\n        public bool HasLocale(Language language)\n        {\n            return LocaleItems.Any(x => x.Language == language);\n        }\n\n        /// <summary>\n        /// Gets localized value if exist regarding to given language.\n        /// </summary>\n        /// <returns>True if exist; otherwise False</returns>\n        public bool TryGetLocaleValue(Language language, out T value)\n        {\n            int index = Array.FindIndex(TypedLocaleItems, x => x.Language == language);\n            if (index >= 0)\n            {\n                value = TypedLocaleItems[index].Value;\n                return true;\n            }\n\n            value = default;\n            return false;\n        }\n\n        /// <summary>\n        /// Returns LocalizedAsset value.\n        /// </summary>\n        /// <param name=\"asset\">LocalizedAsset</param>\n        public static implicit operator T(LocaleVariable<T> asset)\n        {\n            return asset ? asset.Value : default;\n        }\n\n        public override Type GetGenericType => typeof(T);\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b7226a36e35142058fdda749745c14e3\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleVideoClip.cs",
    "content": "using System;\nusing System.Linq;\nusing UnityEngine;\nusing UnityEngine.Video;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Localization\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Localization/VideoClip\", fileName = \"videoclip_localizevalue\", order = 8)]\n    [EditorIcon(\"scriptable_yellow_videoclip\")]\n    public class LocaleVideoClip : LocaleVariable<VideoClip>\n    {\n        [Serializable]\n        private class VideoClipLocaleItem : LocaleItem<VideoClip>\n        {\n        };\n\n        [SerializeField] private VideoClipLocaleItem[] items = new VideoClipLocaleItem[1];\n\n        // ReSharper disable once CoVariantArrayConversion\n        public override LocaleItemBase[] LocaleItems => items;\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/LocaleVideoClip.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 00a0dc7355054137b8ab518f1fe0e443\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: a3d36db6a75640543bcec2d532f8498d, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/ScriptableLocaleBase.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public abstract class ScriptableLocaleBase : ScriptableObject\n    {\n        /// <summary>\n        /// Gets the read-only locale items.\n        /// </summary>\n        public abstract LocaleItemBase[] LocaleItems { get; }\n\n        /// <summary>\n        /// Gets the value type.\n        /// </summary>\n        public abstract Type GetGenericType { get; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable/ScriptableLocaleBase.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c1ae0dd6c1624e26bf027ad29c93dde1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement/Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 7d46e937b5184e84b34422baea51d6ab\ntimeCreated: 1700728721"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Implement.meta",
    "content": "fileFormatVersion: 2\nguid: 898d16718da54a7fa8ae5dab58e7a490\ntimeCreated: 1700728709"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Language.cs",
    "content": "﻿using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public class Language : IEquatable<Language>\n    {\n        public static Language[] BuiltInLanguages\n        {\n            get\n            {\n                return new[]\n                {\n                    Afrikaans, Arabic, Basque, Belarusian, Bulgarian, Catalan, Chinese, Czech, Danish, Dutch, English, Estonian, Faroese, Finnish, French, German,\n                    Greek, Hebrew, Hungarian, Icelandic, Indonesian, Italian, Japanese, Korean, Latvian, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,\n                    SerboCroatian, Slovak, Slovenian, Spanish, Swedish, Thai, Turkish, Ukrainian, Vietnamese\n                };\n            }\n        }\n\n        public static Language Afrikaans => new(SystemLanguage.Afrikaans.ToString(), \"af\");\n        public static Language Arabic => new(SystemLanguage.Arabic.ToString(), \"ar\");\n        public static Language Basque => new(SystemLanguage.Basque.ToString(), \"eu\");\n        public static Language Belarusian => new(SystemLanguage.Belarusian.ToString(), \"be\");\n        public static Language Bulgarian => new(SystemLanguage.Bulgarian.ToString(), \"bg\");\n        public static Language Catalan => new(SystemLanguage.Catalan.ToString(), \"ca\");\n        public static Language Chinese => new(SystemLanguage.Chinese.ToString(), \"zh\");\n        public static Language Czech => new(SystemLanguage.Czech.ToString(), \"cs\");\n        public static Language Danish => new(SystemLanguage.Danish.ToString(), \"da\");\n        public static Language Dutch => new(SystemLanguage.Dutch.ToString(), \"nl\");\n        public static Language English => new(SystemLanguage.English.ToString(), \"en\");\n        public static Language Estonian => new(SystemLanguage.Estonian.ToString(), \"et\");\n        public static Language Faroese => new(SystemLanguage.Faroese.ToString(), \"fo\");\n        public static Language Finnish => new(SystemLanguage.Finnish.ToString(), \"fi\");\n        public static Language French => new(SystemLanguage.French.ToString(), \"fr\");\n        public static Language German => new(SystemLanguage.German.ToString(), \"de\");\n        public static Language Greek => new(SystemLanguage.Greek.ToString(), \"el\");\n        public static Language Hebrew => new(SystemLanguage.Hebrew.ToString(), \"he\");\n        public static Language Hungarian => new(SystemLanguage.Hungarian.ToString(), \"hu\");\n        public static Language Icelandic => new(SystemLanguage.Icelandic.ToString(), \"is\");\n        public static Language Indonesian => new(SystemLanguage.Indonesian.ToString(), \"id\");\n        public static Language Italian => new(SystemLanguage.Italian.ToString(), \"it\");\n        public static Language Japanese => new(SystemLanguage.Japanese.ToString(), \"ja\");\n        public static Language Korean => new(SystemLanguage.Korean.ToString(), \"ko\");\n        public static Language Latvian => new(SystemLanguage.Latvian.ToString(), \"lv\");\n        public static Language Lithuanian => new(SystemLanguage.Lithuanian.ToString(), \"lt\");\n        public static Language Norwegian => new(SystemLanguage.Norwegian.ToString(), \"no\");\n        public static Language Polish => new(SystemLanguage.Polish.ToString(), \"pl\");\n        public static Language Portuguese => new(SystemLanguage.Portuguese.ToString(), \"pt\");\n        public static Language Romanian => new(SystemLanguage.Romanian.ToString(), \"ro\");\n        public static Language Russian => new(SystemLanguage.Russian.ToString(), \"ru\");\n        public static Language SerboCroatian => new(SystemLanguage.SerboCroatian.ToString(), \"hr\");\n        public static Language Slovak => new(SystemLanguage.Slovak.ToString(), \"sk\");\n        public static Language Slovenian => new(SystemLanguage.Slovenian.ToString(), \"sl\");\n        public static Language Spanish => new(SystemLanguage.Spanish.ToString(), \"es\");\n        public static Language Swedish => new(SystemLanguage.Swedish.ToString(), \"sv\");\n        public static Language Thai => new(SystemLanguage.Thai.ToString(), \"th\");\n        public static Language Turkish => new(SystemLanguage.Turkish.ToString(), \"tr\");\n        public static Language Ukrainian => new(SystemLanguage.Ukrainian.ToString(), \"uk\");\n        public static Language Vietnamese => new(SystemLanguage.Vietnamese.ToString(), \"vi\");\n\n        [SerializeField] private string name;\n        [SerializeField] private string code;\n        [SerializeField] private bool custom;\n\n        public string Name => name;\n        public string Code => code;\n        public bool Custom => custom;\n\n        public Language(string name, string code, bool custom = false)\n        {\n            this.name = name ?? \"\";\n            this.code = code ?? \"\";\n            this.custom = custom;\n        }\n\n        public bool Equals(Language other)\n        {\n            if (ReferenceEquals(null, other)) return false;\n            if (ReferenceEquals(this, other)) return true;\n            return Code == other.Code;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (ReferenceEquals(null, obj)) return false;\n            if (ReferenceEquals(this, obj)) return true;\n            if (obj.GetType() != this.GetType()) return false;\n            return Equals((Language)obj);\n        }\n\n        public override int GetHashCode()\n        {\n            return Code.GetHashCode();\n        }\n\n        public static bool operator ==(Language left, Language right)\n        {\n            return Equals(left, right);\n        }\n\n        public static bool operator !=(Language left, Language right)\n        {\n            return !Equals(left, right);\n        }\n\n        public override string ToString()\n        {\n            return Name;\n        }\n\n        public static implicit operator Language(SystemLanguage systemLanguage)\n        {\n            int index = Array.FindIndex(BuiltInLanguages, x => x.name == systemLanguage.ToString());\n            return index >= 0 ? BuiltInLanguages[index] : English;\n        }\n\n        public static explicit operator SystemLanguage(Language language)\n        {\n            if (language.custom) return SystemLanguage.Unknown;\n\n            var systemLanguages = (SystemLanguage[])Enum.GetValues(typeof(SystemLanguage));\n            int index = Array.FindIndex(systemLanguages, x => x.ToString() == language.Name);\n            return index >= 0 ? systemLanguages[index] : SystemLanguage.Unknown;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Language.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f4c852d065584f4fa9b0a18d3c64bad8\ntimeCreated: 1700644636"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Locale.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.DataStorage;\n\nnamespace VirtueSky.Localization\n{\n    public sealed class Locale\n    {\n        private static Locale instance;\n        private Language _currentLanguage = Language.English;\n\n        /// <summary>\n        /// Raised when <see cref=\"CurrentLanguage\"/> has been changed. \n        /// </summary>\n        private event EventHandler<LocaleChangedEventArgs> OnLocaleChangedEvent;\n\n        private static Locale Instance\n        {\n            get\n            {\n#if UNITY_EDITOR\n                if (!Application.isPlaying)\n                {\n                    Debug.LogError(\"Locale only avaiable when application playing!\");\n                    return null;\n                }\n#endif\n\n                if (instance == null)\n                {\n                    instance = new Locale();\n                    instance.SetDefaultLanguage();\n                }\n\n                return instance;\n            }\n        }\n\n        public static Language CurrentLanguage\n        {\n            get => Instance._currentLanguage;\n            set\n            {\n                if (Instance._currentLanguage != value)\n                {\n                    Instance._currentLanguage = value;\n                    SetCurrentLanguageCode(value);\n                    var oldValue = Instance._currentLanguage;\n                    Instance._currentLanguage = value;\n                    Instance.OnLanguageChanged(new LocaleChangedEventArgs(oldValue, value));\n                }\n            }\n        }\n\n        public static EventHandler<LocaleChangedEventArgs> LocaleChangedEvent\n        {\n            get => Instance.OnLocaleChangedEvent;\n            set => Instance.OnLocaleChangedEvent = value;\n        }\n\n        private void OnLanguageChanged(LocaleChangedEventArgs e)\n        {\n            OnLocaleChangedEvent?.Invoke(this, e);\n        }\n\n        /// <summary>\n        /// Sets the <see cref=\"CurrentLanguage\"/> as <see cref=\"Application.systemLanguage\"/>.\n        /// </summary>\n        public void SetSystemLanguage()\n        {\n            CurrentLanguage = Application.systemLanguage;\n        }\n\n        /// <summary>\n        /// Sets the <see cref=\"CurrentLanguage\"/> to default language defined in <see cref=\"LocaleSettings\"/>.\n        /// </summary>\n        public void SetDefaultLanguage()\n        {\n            CurrentLanguage = LocaleSettings.AvailableLanguages.FirstOrDefault();\n        }\n\n        /// <summary>\n        /// Finds all localized assets with type given. Finds all assets in the project if in Editor; otherwise,\n        /// finds only that loaded in memory.\n        /// </summary>\n        /// <returns>Array of specified localized assets.</returns>\n        public static T[] FindAllLocalizedAssets<T>() where T : ScriptableLocaleBase\n        {\n#if UNITY_EDITOR\n            string[] guids = UnityEditor.AssetDatabase.FindAssets($\"t:{typeof(T)}\");\n            var assets = new T[guids.Length];\n            for (var i = 0; i < guids.Length; ++i)\n            {\n                string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[i]);\n                assets[i] = UnityEditor.AssetDatabase.LoadAssetAtPath<T>(assetPath);\n                Debug.Assert(assets[i]);\n            }\n\n            return assets;\n#else\n            return Resources.FindObjectsOfTypeAll<T>();\n#endif\n        }\n\n        /// <summary>\n        /// Finds all localized assets.\n        /// </summary>\n        /// <seealso cref=\"FindAllLocalizedAssets{T}\"/>\n        /// <returns>Array of localized assets.</returns>\n        public static ScriptableLocaleBase[] FindAllLocalizedAssets()\n        {\n            return FindAllLocalizedAssets<ScriptableLocaleBase>();\n        }\n\n        const string KEY_LANGUAGE = \"KEY_LANGUAGE\";\n        public static string GetCurrentLanguageCode() => GameData.Get(KEY_LANGUAGE, \"\");\n        public static void SetCurrentLanguageCode(Language language) => GameData.Set(KEY_LANGUAGE, language.Code);\n        public static void SetCurrentLanguageCode(string languageCode) => GameData.Set(KEY_LANGUAGE, languageCode);\n\n        public static void LoadLanguageSetting()\n        {\n            var list = LocaleSettings.AvailableLanguages;\n            string lang = GetCurrentLanguageCode();\n            // for first time when user not choose lang to display\n            // use system language, if you don't use detect system language use first language in list available laguages\n            if (string.IsNullOrEmpty(lang))\n            {\n                var index = 0;\n                if (LocaleSettings.DetectDeviceLanguage)\n                {\n                    var nameSystemLang = UnityEngine.Application.systemLanguage.ToString();\n                    index = list.FindIndex(x => x.Name == nameSystemLang);\n                    if (index < 0) index = 0;\n                }\n\n                lang = list[index].Code;\n                SetCurrentLanguageCode(lang);\n            }\n\n            int i = list.FindIndex(x => x.Code == lang);\n            Locale.CurrentLanguage = list[i];\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Locale.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a71f9cb605674f52bb2028bbb37a4672\ntimeCreated: 1700707788"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleChangedEventArgs.cs",
    "content": "using System;\n\nnamespace VirtueSky.Localization\n{\n    public class LocaleChangedEventArgs : EventArgs\n    {\n        public LocaleChangedEventArgs(Language previous, Language current)\n        {\n            Previous = previous;\n            Current = current;\n        }\n\n        public Language Previous { get; private set; }\n        public Language Current { get; private set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleChangedEventArgs.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e485a91b41894d0da5e125509c7a1afc\ntimeCreated: 1700721928"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleItem.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public class LocaleItem<T> : LocaleItemBase\n    {\n        [SerializeField] private T value;\n\n        public T Value\n        {\n            get => value;\n            set => this.value = value;\n        }\n\n        public override object ObjectValue\n        {\n            get => value;\n            set => this.value = (T)value;\n        }\n\n        public LocaleItem()\n        {\n        }\n\n        public LocaleItem(Language language, T value)\n        {\n            Language = language;\n            Value = value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleItem.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4756bcf8dc22492fb771f98af7db141b\ntimeCreated: 1700705854"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleItemBase.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public abstract class LocaleItemBase\n    {\n        [SerializeField] private Language language = Language.English;\n\n        public Language Language\n        {\n            get => language;\n            set => language = value;\n        }\n\n        public abstract object ObjectValue { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleItemBase.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3b558057d4e74740a2d510f527cf894b\ntimeCreated: 1700705405"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleSettings.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Linq;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Localization\n{\n    [EditorIcon(\"icon_scriptable\")]\n    public sealed class LocaleSettings : ScriptableSettings<LocaleSettings>\n    {\n        [SerializeField] private List<Language> availableLanguages = new(1) { Language.English };\n        [SerializeField] private bool detectDeviceLanguage;\n        [SerializeField] private string importLocation = \"Assets/_Sunflower/Scriptable/Localization\";\n        [SerializeField] private string googleTranslateApiKey;\n        [SerializeField] private string spreadsheetKey;\n        [SerializeField, TextArea] private string serviceAccountCredential;\n\n        public static bool DetectDeviceLanguage => Instance.detectDeviceLanguage;\n        public static string ImportLocation => Instance.importLocation;\n        public static List<Language> AvailableLanguages => Instance.availableLanguages;\n        public static string GoogleTranslateApiKey => Instance.googleTranslateApiKey;\n        public static string SpreadsheetKey => Instance.spreadsheetKey;\n        public static string ServiceAccountCredential => Instance.serviceAccountCredential;\n\n        public static List<Language> AllLanguages\n        {\n            get\n            {\n                var languages = new List<Language>();\n                languages.AddRange(Language.BuiltInLanguages);\n                languages.AddRange(AvailableLanguages.Filter(l => l.Custom));\n                return languages;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/LocaleSettings.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f4d69dc1bc6643cb8580d1dd9e553e92\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate/GoogleTranslateRequest.cs",
    "content": "using System;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public class GoogleTranslateRequest\n    {\n        public Language source;\n        public Language target;\n        public string value;\n\n        public GoogleTranslateRequest()\n        {\n        }\n\n        public GoogleTranslateRequest(Language source, Language target, string value)\n        {\n            this.source = source;\n            this.target = target;\n            this.value = value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate/GoogleTranslateRequest.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1ee312ff8d9b8c41aa5182095361b3a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate/GoogleTranslateResponse.cs",
    "content": "using System;\n\nnamespace VirtueSky.Localization\n{\n    [Serializable]\n    public class GoogleTranslateResponse\n    {\n        public string translatedText;\n        public string detectedSourceLanguage;\n\n        public GoogleTranslateResponse()\n        {\n        }\n\n        public GoogleTranslateResponse(string translatedText)\n        {\n            this.translatedText = translatedText;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate/GoogleTranslateResponse.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 017db063730c427aa1deeb09d59f690c\ntimeCreated: 1701241276"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate/GoogleTranslator.cs",
    "content": "using System;\nusing System.Collections;\nusing UnityEngine;\nusing UnityEngine.Networking;\n\nnamespace VirtueSky.Localization\n{\n    public sealed class GoogleTranslator\n    {\n        private const string REQUEST_URL_V2 = \"https://translation.googleapis.com/language/translate/v2?key={0}\";\n        private const string REQUEST_KEY_INPUT_TEXT = \"q\";\n        private const string REQUEST_KEY_SOURCE_LANGUAGE = \"source\";\n        private const string REQUEST_KEY_TARGET_LANGUAGE = \"target\";\n\n        /// <summary>\n        /// Gets or sets the google cloud API key.\n        /// </summary>\n        /// <seealso cref=\"http://cloud.google.com/docs/authentication/api-keys\"/>\n        public string AuthCredential { get; set; }\n\n        public GoogleTranslator(string authCredential)\n        {\n            AuthCredential = authCredential;\n        }\n\n        /// <summary>\n        /// Performs translation with given translate request asynchronous.\n        /// </summary>\n        /// <param name=\"request\">Translate request.</param>\n        /// <param name=\"onCompleted\">Completed action.</param>\n        /// <param name=\"onError\">Error action.</param>\n        public IEnumerator TranslateAsync(\n            GoogleTranslateRequest request,\n            Action<TranslationCompletedEventArgs> onCompleted = null,\n            Action<TranslationErrorEventArgs> onError = null)\n        {\n            using (var www = PrepareRequest(request))\n            {\n#if UNITY_2017_2_OR_NEWER\n                yield return www.SendWebRequest();\n#else\n                yield return www.Send();\n#endif\n                ProcessResponse(request, www, onCompleted, onError);\n            }\n        }\n\n        /// <summary>\n        /// Useful for Editor scripts. Otherwise, recommended to use <see cref=\"TranslateAsync\"/>.\n        /// </summary>\n        /// <param name=\"request\">Translate request.</param>\n        /// <param name=\"onCompleted\">Completed action.</param>\n        /// <param name=\"onError\">Error action.</param>\n        public void Translate(GoogleTranslateRequest request, Action<TranslationCompletedEventArgs> onCompleted = null, Action<TranslationErrorEventArgs> onError = null)\n        {\n            using (var www = PrepareRequest(request))\n            {\n#if UNITY_2017_2_OR_NEWER\n                www.SendWebRequest();\n#else\n                www.Send();\n#endif\n\n                // Wait request completion.\n                while (!www.isDone)\n                {\n                }\n\n                ProcessResponse(request, www, onCompleted, onError);\n            }\n        }\n\n        private UnityWebRequest PrepareRequest(GoogleTranslateRequest request)\n        {\n            if (request == null) throw new ArgumentNullException(nameof(request));\n\n            if (string.IsNullOrEmpty(AuthCredential))\n            {\n                // ReSharper disable once NotResolvedInText\n                throw new ArgumentNullException(\"AuthCredential\", \"Auth credential missing!\");\n            }\n\n            var form = new WWWForm();\n            form.AddField(REQUEST_KEY_INPUT_TEXT, request.value);\n            form.AddField(REQUEST_KEY_SOURCE_LANGUAGE, request.source.Code);\n            form.AddField(REQUEST_KEY_TARGET_LANGUAGE, request.target.Code);\n\n            var url = string.Format(REQUEST_URL_V2, AuthCredential);\n            return UnityWebRequest.Post(url, form);\n        }\n\n        private void ProcessResponse(\n            GoogleTranslateRequest request,\n            UnityWebRequest www,\n            Action<TranslationCompletedEventArgs> onCompleted,\n            Action<TranslationErrorEventArgs> onError)\n        {\n            if (www.result is UnityWebRequest.Result.ConnectionError or UnityWebRequest.Result.ProtocolError)\n            {\n                onError?.Invoke(new TranslationErrorEventArgs(www.error, www.responseCode));\n            }\n            else\n            {\n                var response = JsonUtility.FromJson<JsonResponse>(www.downloadHandler.text);\n                if (response is { data: { translations: { Length: > 0 } } })\n                {\n                    var requests = new[] { request };\n\n                    var translateResponse = new GoogleTranslateResponse { translatedText = response.data.translations[0].translatedText };\n                    var responses = new[] { translateResponse };\n\n                    onCompleted?.Invoke(new TranslationCompletedEventArgs(requests, responses));\n                }\n                else\n                {\n                    if (response != null && response.error != null)\n                    {\n                        onError?.Invoke(new TranslationErrorEventArgs(response.error.message, response.error.code));\n                    }\n\n                    onError?.Invoke(new TranslationErrorEventArgs(\"Response data could not be read.\", -1));\n                }\n            }\n        }\n\n        [Serializable]\n        private class JsonResponse\n        {\n            public JsonData data = null;\n            public JsonError error = null;\n        }\n\n        [Serializable]\n        private class JsonData\n        {\n            public JsonTranslation[] translations = null;\n        }\n\n        [Serializable]\n        private class JsonError\n        {\n            public int code = 0;\n            public string message = null;\n        }\n\n        [Serializable]\n        private class JsonTranslation\n        {\n            public string translatedText = \"\";\n            public string detectedSourceLanguage = \"\";\n        }\n    }\n\n    /// <summary>\n    /// Provides the requests and translation responses.\n    /// </summary>\n    public class TranslationCompletedEventArgs : EventArgs\n    {\n        /// <summary>\n        /// Translate requests.\n        /// </summary>\n        public GoogleTranslateRequest[] Requests { get; private set; }\n\n        /// <summary>\n        /// Translate responses.\n        /// </summary>\n        public GoogleTranslateResponse[] Responses { get; private set; }\n\n        public TranslationCompletedEventArgs(GoogleTranslateRequest[] requests, GoogleTranslateResponse[] responses)\n        {\n            Debug.Assert(requests != null);\n            Debug.Assert(responses != null);\n            Requests = requests;\n            Responses = responses;\n        }\n    }\n\n    /// <summary>\n    /// Provides detailed information upon translation errors.\n    /// </summary>\n    public class TranslationErrorEventArgs : EventArgs\n    {\n        /// <summary>\n        /// Error code.\n        /// </summary>\n        public long ResponseCode { get; private set; }\n\n        /// <summary>\n        /// Error message.\n        /// </summary>\n        public string Message { get; private set; }\n\n        public TranslationErrorEventArgs(string message, long responseCode)\n        {\n            ResponseCode = responseCode;\n            Message = message;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate/GoogleTranslator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 421898eccc5b4bd8800940b882b63994\ntimeCreated: 1701241382"
  },
  {
    "path": "VirtueSky/Localization/Runtime/Translate.meta",
    "content": "fileFormatVersion: 2\nguid: 241b88041d83c1d42a2be9d6d6bc2fc4\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime/VirtueSky.Sunflower.Localization.asmdef",
    "content": "{\n    \"name\": \"VirtueSky.Sunflower.Localization\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:efdee36e63e4ce34a91071531ec746c1\",\n        \"GUID:6055be8ebefd69e48b49212b09b47b2f\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:32dbaa332e571bf429b7de517f75f074\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Localization/Runtime/VirtueSky.Sunflower.Localization.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: c7e7793e0b5d326429f90e6fd716775e\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 398dc987f9c00a140bf71180081694b0\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Localization.meta",
    "content": "fileFormatVersion: 2\nguid: 4e2227bb265fbe64bab7f2d4a5c08a8e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Misc/Common.Animancer.cs",
    "content": "using System;\n\n#if VIRTUESKY_ANIMANCER\nusing Animancer;\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        public static AnimancerComponent PlayClip(this AnimancerComponent animancerComponent, ClipTransition clip,\n            Action _endAnim = null, float _durationFade = .2f, bool isCheckPlayingClip = true,\n            FadeMode mode = default, object _owner = null)\n        {\n            if (isCheckPlayingClip)\n            {\n                if (!animancerComponent.IsPlaying(clip))\n                {\n                    Handle();\n                }\n            }\n            else\n            {\n                Handle();\n            }\n\n            void Handle()\n            {\n                var state = animancerComponent.Play(clip, clip.Clip.length * _durationFade, mode);\n                if (_endAnim != null)\n                {\n                    object owner = _owner ?? animancerComponent;\n                    state.Events(owner).OnEnd += OnEndAnim;\n\n                    void OnEndAnim()\n                    {\n                        state.Events(owner).OnEnd -= OnEndAnim;\n                        _endAnim?.Invoke();\n                    }\n                }\n            }\n\n            return animancerComponent;\n        }\n\n        // Freeze a single animation on its current frame:\n        public static AnimancerComponent PauseClip(this AnimancerComponent animancerComponent, ClipTransition clip)\n        {\n            animancerComponent.States[clip].IsPlaying = false;\n            return animancerComponent;\n        }\n\n        // Freeze all animations on their current frame:\n        public static AnimancerComponent PauseAll(this AnimancerComponent animancerComponent)\n        {\n            animancerComponent.Graph.PauseGraph();\n            return animancerComponent;\n        }\n\n        // Stop a single animation from affecting the character and rewind it to the start:\n        public static AnimancerComponent StopClip(this AnimancerComponent animancerComponent, ClipTransition clip)\n        {\n            animancerComponent.Stop(clip);\n\n            // Or you can call it on the state directly:\n            var state = animancerComponent.States[clip];\n            state.Stop();\n            return animancerComponent;\n        }\n\n        // Stop all animations from affecting the character and rewind them to the start:\n        public static AnimancerComponent StopAll(this AnimancerComponent animancerComponent)\n        {\n            animancerComponent.Stop();\n            return animancerComponent;\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Misc/Common.Animancer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ecabf26c8cd44aeb094d2342c0e2d47\ntimeCreated: 1708072435"
  },
  {
    "path": "VirtueSky/Misc/Common.Collections.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\n\nnamespace VirtueSky.Misc\n{\n    public partial class Common\n    {\n        public static void Clear<T>(this T[] collection)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n            Array.Clear(collection, 0, collection.Length);\n        }\n\n        #region IsNullOrEmpty\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsNullOrEmpty<T>(this List<T> source)\n        {\n            return source == null || source.Count == 0;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsNullOrEmpty<T>(this T[] source)\n        {\n            return source == null || source.Length == 0;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsNullOrEmpty<TKey, TValue>(this Dictionary<TKey, TValue> source)\n        {\n            return source == null || source.Keys.Count == 0;\n        }\n\n        #endregion\n\n        #region Shuffle\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Shuffle<T>(this T[] source)\n        {\n            int n = source.Length;\n            while (n > 1)\n            {\n                n--;\n                int k = UnityEngine.Random.Range(0, n);\n                (source[k], source[n]) = (source[n], source[k]);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Shuffle<T>(this List<T> source)\n        {\n            int n = source.Count;\n            while (n > 1)\n            {\n                n--;\n                int k = UnityEngine.Random.Range(0, n);\n                (source[k], source[n]) = (source[n], source[k]);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static IDictionary<T1, T2> Shuffle<T1, T2>(this IDictionary<T1, T2> source)\n        {\n            var keys = source.Keys.ToArray();\n            var values = source.Values.ToArray();\n\n            int n = source.Count;\n            while (n > 1)\n            {\n                n--;\n                int k = UnityEngine.Random.Range(0, n);\n                (keys[k], keys[n]) = (keys[n], keys[k]);\n                (values[k], values[n]) = (values[n], values[k]);\n            }\n\n            return MakeDictionary(keys, values);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static IDictionary<TKey, TValue> MakeDictionary<TKey, TValue>(this TKey[] keys, TValue[] values)\n        {\n            if (keys == null) throw new ArgumentNullException(nameof(keys));\n            if (values == null) throw new ArgumentNullException(nameof(values));\n            if (keys.Length != values.Length) throw new ArgumentException(\"Size keys and size values diffirent!\");\n\n            IDictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();\n            for (var i = 0; i < keys.Length; i++)\n            {\n                result.Add(keys[i], values[i]);\n            }\n\n            return result;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static IDictionary<TKey, TValue> MakeDictionary<TKey, TValue>(this IList<TKey> keys,\n            IList<TValue> values)\n        {\n            if (keys == null) throw new ArgumentNullException(nameof(keys));\n            if (values == null) throw new ArgumentNullException(nameof(values));\n            if (keys.Count != values.Count) throw new ArgumentException(\"Size keys and size values diffirent!\");\n\n            IDictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();\n            for (var i = 0; i < keys.Count; i++)\n            {\n                result.Add(keys[i], values[i]);\n            }\n\n            return result;\n        }\n\n        #endregion\n\n        #region Pick random\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T PickRandom<T>(this T[] collection)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n\n            return collection.Length == 0 ? default : collection[UnityEngine.Random.Range(0, collection.Length)];\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T PickRandom<T>(this List<T> collection)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n\n            return collection.Count == 0 ? default : collection[UnityEngine.Random.Range(0, collection.Count)];\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static (T, int) PickRandomAndIndex<T>(this T[] collection)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n\n            int index = UnityEngine.Random.Range(0, collection.Length);\n            return collection.Length == 0 ? (default, -1) : (collection[index], index);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static (T, int) PickRandomWithIndex<T>(this List<T> collection)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n\n            var index = UnityEngine.Random.Range(0, collection.Count);\n            return collection.Count == 0 ? (default, -1) : (collection[index], index);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static List<T> PickRandomSubList<T>(this List<T> collection, int length)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n            var listTemp = collection.ToList();\n            List<T> pickList = new List<T>();\n            listTemp.Shuffle();\n            for (int i = 0; i < listTemp.Count; i++)\n            {\n                if (i < length) pickList.Add(listTemp[i]);\n            }\n\n            return pickList;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T[] PickRandomSubArray<T>(this T[] collection, int length)\n        {\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n            T[] arrayTemp = new T[collection.Length];\n            Array.Copy(collection, arrayTemp, collection.Length);\n            T[] pickArray = new T[length <= collection.Length ? length : collection.Length];\n            arrayTemp.Shuffle();\n            for (int i = 0; i < arrayTemp.Length; i++)\n            {\n                if (i < length) pickArray[i] = arrayTemp[i];\n            }\n\n            return pickArray;\n        }\n\n        #endregion\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Swap<T>(this T[] source, int oldIndex, int newIndex)\n        {\n            if (oldIndex < 0 || newIndex < 0 || oldIndex > source.Length || newIndex > source.Length)\n            {\n#if UNITY_EDITOR\n                UnityEngine.Debug.LogError(\"Index out of range!\");\n#endif\n                return;\n            }\n\n            if (oldIndex == newIndex) return;\n            (source[oldIndex], source[newIndex]) = (source[newIndex], source[oldIndex]);\n        }\n\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Swap<T>(this List<T> source, int oldIndex, int newIndex)\n        {\n            if (oldIndex < 0 || newIndex < 0 || oldIndex > source.Count || newIndex > source.Count)\n            {\n#if UNITY_EDITOR\n                UnityEngine.Debug.LogError(\"Index out of range!\");\n#endif\n                return;\n            }\n\n            if (oldIndex == newIndex) return;\n            (source[oldIndex], source[newIndex]) = (source[newIndex], source[oldIndex]);\n        }\n\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T[] ForEach<T>(this T[] source, Action<T> action)\n        {\n            for (int i = source.Length - 1; i >= 0; i--)\n            {\n                action(source[i]);\n            }\n\n            return source;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static List<T> ForEach<T>(this List<T> source, Action<T> action)\n        {\n            for (int i = source.Count - 1; i >= 0; i--)\n            {\n                action(source[i]);\n            }\n\n            return source;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static T[] ForEach<T>(this T[] source, Action<T, int> action)\n        {\n            for (int i = source.Length - 1; i >= 0; i--)\n            {\n                action(source[i], i);\n            }\n\n            return source;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static List<T> ForEach<T>(this List<T> source, Action<T, int> action)\n        {\n            for (int i = source.Count - 1; i >= 0; i--)\n            {\n                action(source[i], i);\n            }\n\n            return source;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Removes<T>(this List<T> source, List<T> entries)\n        {\n            for (var i = 0; i < entries.Count; i++)\n            {\n                source.Remove(entries[i]);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static void Removes<T>(this List<T> source, T[] entries)\n        {\n            foreach (var item in entries)\n            {\n                source.Remove(item);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static List<T> Adds<T>(this List<T> source, List<T> entries)\n        {\n            for (int i = 0; i < entries.Count; i++)\n            {\n                source.Add(entries[i]);\n            }\n\n            return source;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static List<T> Adds<T>(this List<T> source, T[] entries)\n        {\n            foreach (var e in entries)\n            {\n                source.Add(e);\n            }\n\n            return source;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Collections.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 17e2f19420454242aa4a49fa031c7c95\ntimeCreated: 1743264883"
  },
  {
    "path": "VirtueSky/Misc/Common.Colors.cs",
    "content": "using System.Runtime.CompilerServices;\nusing UnityEngine;\nusing UnityEngine.UI;\n\nnamespace VirtueSky.Misc\n{\n    public partial class Common\n    {\n        public static Color SetAlpha(this Color color, float a)\n        {\n            color.a = a;\n            return color;\n        }\n\n        public static Color SetRelativeAlpha(this Color color, float a)\n        {\n            color.a += a;\n            return color;\n        }\n\n        public static Color SetRed(this Color color, float r)\n        {\n            color.r = r;\n            return color;\n        }\n\n        public static Color SetRelativeRed(this Color color, float r)\n        {\n            color.r += r;\n            return color;\n        }\n\n        public static Color SetGreen(this Color color, float g)\n        {\n            color.g = g;\n            return color;\n        }\n\n        public static Color SetRelativeGreen(this Color color, float g)\n        {\n            color.g += g;\n            return color;\n        }\n\n        public static Color SetBlue(this Color color, float b)\n        {\n            color.b = b;\n            return color;\n        }\n\n        public static Color SetRelativeBlue(this Color color, float b)\n        {\n            color.b += b;\n            return color;\n        }\n\n        public static Graphic SetAlpha(this Graphic graphic, float a)\n        {\n            var colorCache = graphic.color;\n            colorCache.a = a;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetRelativeAlpha(this Graphic graphic, float a)\n        {\n            var colorCache = graphic.color;\n            colorCache.a += a;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetRed(this Graphic graphic, float r)\n        {\n            var colorCache = graphic.color;\n            colorCache.r = r;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetRelativeRed(this Graphic graphic, float r)\n        {\n            var colorCache = graphic.color;\n            colorCache.r += r;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetGreen(this Graphic graphic, float g)\n        {\n            var colorCache = graphic.color;\n            colorCache.g = g;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetRelativeGreen(this Graphic graphic, float g)\n        {\n            var colorCache = graphic.color;\n            colorCache.g += g;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetBlue(this Graphic graphic, float b)\n        {\n            var colorCache = graphic.color;\n            colorCache.b = b;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static Graphic SetRelativeBlue(this Graphic graphic, float b)\n        {\n            var colorCache = graphic.color;\n            colorCache.b += b;\n            graphic.color = colorCache;\n            return graphic;\n        }\n\n        public static SpriteRenderer SetAlpha(this SpriteRenderer renderer, float a)\n        {\n            var colorCache = renderer.color;\n            colorCache.a = a;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetRelativeAlpha(this SpriteRenderer renderer, float a)\n        {\n            var colorCache = renderer.color;\n            colorCache.a += a;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetRed(this SpriteRenderer renderer, float r)\n        {\n            var colorCache = renderer.color;\n            colorCache.r = r;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetRelativeRed(this SpriteRenderer renderer, float r)\n        {\n            var colorCache = renderer.color;\n            colorCache.r += r;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetGreen(this SpriteRenderer renderer, float g)\n        {\n            var colorCache = renderer.color;\n            colorCache.g = g;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetRelativeGreen(this SpriteRenderer renderer, float g)\n        {\n            var colorCache = renderer.color;\n            colorCache.g += g;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetBlue(this SpriteRenderer renderer, float b)\n        {\n            var colorCache = renderer.color;\n            colorCache.b = b;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n        public static SpriteRenderer SetRelativeBlue(this SpriteRenderer renderer, float b)\n        {\n            var colorCache = renderer.color;\n            colorCache.b += b;\n            renderer.color = colorCache;\n            return renderer;\n        }\n\n\n        /// <summary>\n        ///   <para>Returns the color as a hexadecimal string in the format \"#RRGGBB\".</para>\n        /// </summary>\n        /// <param name=\"color\">The color to be converted.</param>\n        /// <returns>\n        ///   <para>Hexadecimal string representing the color.</para>\n        /// </returns>\n        public static string ToHtmlStringRGB(this Color color)\n        {\n            var color32 = new Color32((byte)Mathf.Clamp(Mathf.RoundToInt(color.r * byte.MaxValue), 0, byte.MaxValue),\n                (byte)Mathf.Clamp(Mathf.RoundToInt(color.g * byte.MaxValue), 0, byte.MaxValue),\n                (byte)Mathf.Clamp(Mathf.RoundToInt(color.b * byte.MaxValue), 0, byte.MaxValue),\n                1);\n\n            return \"#{0:X2}{1:X2}{2:X2}\".Format(color32.r, color32.g, color32.b);\n        }\n\n\n        /// <summary>\n        ///   <para>Returns the color as a hexadecimal string in the format \"#RRGGBBAA\".</para>\n        /// </summary>\n        /// <param name=\"color\">The color to be converted.</param>\n        /// <returns>\n        ///   <para>Hexadecimal string representing the color.</para>\n        /// </returns>\n        // ReSharper disable once InconsistentNaming\n        public static string ToHtmlStringRGBA(this Color color)\n        {\n            var color32 = new Color32((byte)Mathf.Clamp(Mathf.RoundToInt(color.r * byte.MaxValue), 0, byte.MaxValue),\n                (byte)Mathf.Clamp(Mathf.RoundToInt(color.g * byte.MaxValue), 0, byte.MaxValue),\n                (byte)Mathf.Clamp(Mathf.RoundToInt(color.b * byte.MaxValue), 0, byte.MaxValue),\n                (byte)Mathf.Clamp(Mathf.RoundToInt(color.a * byte.MaxValue), 0, byte.MaxValue));\n\n            return \"#{0:X2}{1:X2}{2:X2}{3:X2}\".Format(color32.r, color32.g, color32.b, color32.a);\n        }\n\n\n        public static bool TryParseHtmlString(this string htmlString, out Color color)\n        {\n            string stringColor = htmlString;\n            if (!stringColor[0].Equals('#')) stringColor = stringColor.Insert(0, \"#\");\n            return ColorUtility.TryParseHtmlString(stringColor, out color);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Colors.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9a7d161837414c7d926cabd0ae959477\ntimeCreated: 1712478827"
  },
  {
    "path": "VirtueSky/Misc/Common.Math.cs",
    "content": "using System.Runtime.CompilerServices;\nusing UnityEngine;\n\nnamespace VirtueSky.Misc\n{\n    public partial class Common\n    {\n        #region Constants\n\n        /// <summary>The circle constant. Defined as the circumference of a circle divided by its radius. Equivalent to 2*pi</summary>\n        public const float TWO_PI = 6.28318530717959f;\n\n        /// <summary>An obscure circle constant. Defined as the circumference of a circle divided by its diameter. Equivalent to 0.5*tau</summary>\n        public const float PI = 3.14159265358979f;\n\n        // PI / 2 OR 90 deg\n        public const float PI_2 = 1.5707963267949f;\n\n        // PI / 3 OR 60 deg\n        public const float PI_3 = 1.04719755119659666667f;\n\n        // PI / 4 OR 45 deg\n        public const float PI_4 = 0.785398163397448f;\n\n        // PI / 8 OR 22.5 deg\n        public const float PI_8 = 0.392699081698724f;\n\n        // PI / 16 OR 11.25 deg\n        public const float PI_16 = 0.196349540849362f;\n\n        // 3 * PI_2 OR 270 deg\n        public const float THREE_PI_2 = 4.71238898038469f;\n\n        /// <summary>Euler's number. The base of the natural logarithm. f(x)=e^x is equal to its own derivative</summary>\n        public const float E = 2.71828182845905f;\n\n        /// <summary>The golden ratio. It is the value of a/b where a/b = (a+b)/a. It's the positive root of x^2-x-1</summary>\n        public const float GOLDEN_RATIO = 1.61803398875f;\n\n        /// <summary>The square root of two. The length of the vector (1,1)</summary>\n        public const float SQRT2 = 1.4142135623731f;\n\n        /// <summary>The reciprocal of the square root of two. The components of the vector (1,1)</summary>\n        public const float RSQRT2 = 1f / SQRT2;\n\n        /// <summary>Multiply an angle in degrees by this, to convert it to radians (2pi/360)</summary>\n        public const float DEG_TO_RAD = 0.0174532925199433f;\n\n        /// <summary>Multiply an angle in radians by this, to convert it to degrees (360/2pi)</summary>\n        public const float RAD_TO_DEG = 57.2957795130823f;\n\n        public const double DBL_EPSILON = 9.99999943962493E-11;\n\n        #endregion\n\n        #region Math operations\n\n        /// <summary>Returns the square root of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Sqrt(this float value) => (float)System.Math.Sqrt(value);\n\n        /// <summary>Returns the square root of each component</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Sqrt(this Vector2 v) => new Vector2(Sqrt(v.x), Sqrt(v.y));\n\n        /// <inheritdoc cref=\"Math.Sqrt(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Sqrt(this Vector3 v) => new Vector3(Sqrt(v.x), Sqrt(v.y), Sqrt(v.z));\n\n        /// <inheritdoc cref=\"Math.Sqrt(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Sqrt(this Vector4 v) => new Vector4(Sqrt(v.x), Sqrt(v.y), Sqrt(v.z), Sqrt(v.w));\n\n        /// <summary>Returns <c>value</c> raised to the power of <c>exponent</c></summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Pow(this float value, float exponent) => (float)System.Math.Pow(value, exponent);\n\n        /// <summary>Returns e to the power of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Exp(this float power) => (float)System.Math.Exp(power);\n\n        /// <summary>Returns the logarithm of a value, with the given base</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Log(this float value, float @base) => (float)System.Math.Log(value, @base);\n\n        /// <summary>Returns the natural logarithm of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Log(this float value) => (float)System.Math.Log(value);\n\n        /// <summary>Returns the base 10 logarithm of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Log10(this float value) => (float)System.Math.Log10(value);\n\n        #endregion\n\n        #region Floating Point\n\n        /// <summary>A very small value, used for various floating point inaccuracy thresholds</summary>\n        public static readonly float Epsilon = UnityEngineInternal.MathfInternal.IsFlushToZeroEnabled\n            ? UnityEngineInternal.MathfInternal.FloatMinNormal\n            : UnityEngineInternal.MathfInternal.FloatMinDenormal;\n\n        /// <summary>float.PositiveInfinity</summary>\n        public const float Infinity = float.PositiveInfinity;\n\n        /// <summary>float.NegativeInfinity</summary>\n        public const float NegativeInfinity = float.NegativeInfinity;\n\n        /// <summary>Returns whether or not two values are approximately equal.\n        /// They are considered equal if they are within a <c>M.Epsilon*8</c> or <c>max(a,b)*0.000001f</c> range of each other</summary>\n        /// <param name=\"a\">The first value to compare</param>\n        /// <param name=\"b\">The second value to compare</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool Approximately(this float a, float b) =>\n            Abs(b - a) < Max(0.000001f * Max(Abs(a), Abs(b)), Epsilon * 8);\n\n        /// <inheritdoc cref=\"Approximately(float,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool Approximately(this Vector2 a, Vector2 b) =>\n            Approximately(a.x, b.x) && Approximately(a.y, b.y);\n\n        /// <inheritdoc cref=\"Approximately(float,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool Approximately(this Vector3 a, Vector3 b) =>\n            Approximately(a.x, b.x) && Approximately(a.y, b.y) && Approximately(a.z, b.z);\n\n        /// <inheritdoc cref=\"Approximately(float,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool Approximately(this Vector4 a, Vector4 b) =>\n            Approximately(a.x, b.x) && Approximately(a.y, b.y) && Approximately(a.z, b.z) && Approximately(a.w, b.w);\n\n        /// <inheritdoc cref=\"Approximately(float,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool Approximately(this Color a, Color b) =>\n            Approximately(a.r, b.r) && Approximately(a.g, b.g) && Approximately(a.b, b.b) && Approximately(a.a, b.a);\n\n        #endregion\n\n        #region Trigonometry\n\n        /// <summary>Returns the cosine of the given angle. Equivalent to the x-component of a unit vector with the same angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Cos(this float angRad) => (float)System.Math.Cos(angRad);\n\n        /// <summary>Returns the sine of the given angle. Equivalent to the y-component of a unit vector with the same angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Sin(this float angRad) => (float)System.Math.Sin(angRad);\n\n        /// <summary>Returns the tangent of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Tan(this float angRad) => (float)System.Math.Tan(angRad);\n\n        /// <summary>Returns the arc cosine of the given value, in radians</summary>\n        /// <param name=\"value\">A value between -1 and 1</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Acos(this float value) => (float)System.Math.Acos(value);\n\n        /// <summary>Returns the arc sine of the given value, in radians</summary>\n        /// <param name=\"value\">A value between -1 and 1</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Asin(this float value) => (float)System.Math.Asin(value);\n\n        /// <summary>Returns the arc tangent of the given value, in radians</summary>\n        /// <param name=\"value\">A value between -1 and 1</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Atan(this float value) => (float)System.Math.Atan(value);\n\n        /// <summary>Returns the angle of a vector. I don't recommend using this function, it's confusing~ Use M.DirToAng instead</summary>\n        /// <param name=\"y\">The y component of the vector. They're flipped yeah I know but this is how everyone implements if for some godforsaken reason</param>\n        /// <param name=\"x\">The x component of the vector. They're flipped yeah I know but this is how everyone implements if for some godforsaken reason</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Atan2(this float y, float x) => (float)System.Math.Atan2(y, x);\n\n        /// <summary>Returns the cosecant of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Csc(this float angRad) => 1f / (float)System.Math.Sin(angRad);\n\n        /// <summary>Returns the secant of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Sec(this float angRad) => 1f / (float)System.Math.Cos(angRad);\n\n        /// <summary>Returns the cotangent of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Cot(this float angRad) => 1f / (float)System.Math.Tan(angRad);\n\n        /// <summary>Returns the versine of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Ver(this float angRad) => 1 - (float)System.Math.Cos(angRad);\n\n        /// <summary>Returns the coversine of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Cvs(this float angRad) => 1 - (float)System.Math.Sin(angRad);\n\n        /// <summary>Returns the chord of the given angle</summary>\n        /// <param name=\"angRad\">Angle in radians</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Crd(this float angRad) => 2 * (float)System.Math.Sin(angRad / 2);\n\n        #endregion\n\n        #region Hyperbolic Trigonometry\n\n        /// <summary>Returns the hyperbolic cosine of the given hyperbolic angle</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Cosh(this float x) => (float)System.Math.Cosh(x);\n\n        /// <summary>Returns the hyperbolic sine of the given hyperbolic angle</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Sinh(this float x) => (float)System.Math.Sinh(x);\n\n        /// <summary>Returns the hyperbolic tangent of the given hyperbolic angle</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Tanh(this float x) => (float)System.Math.Tanh(x);\n\n        /// <summary>Returns the hyperbolic arc cosine of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Acosh(this float x) => (float)System.Math.Log(x + Mathf.Sqrt(x * x - 1));\n\n        /// <summary>Returns the hyperbolic arc sine of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Asinh(this float x) => (float)System.Math.Log(x + Mathf.Sqrt(x * x + 1));\n\n        /// <summary>Returns the hyperbolic arc tangent of the given value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Atanh(this float x) => (float)(0.5 * System.Math.Log((1 + x) / (1 - x)));\n\n        #endregion\n\n        #region Absolute Values\n\n        /// <summary>Returns the absolute value. Basically makes negative numbers positive</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Abs(this float value) => System.Math.Abs(value);\n\n        /// <inheritdoc cref=\"Math.Abs(float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Abs(this int value) => System.Math.Abs(value);\n\n        /// <summary>Returns the absolute value, per component. Basically makes negative numbers positive</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Abs(this Vector2 v) => new Vector2(Abs(v.x), Abs(v.y));\n\n        /// <inheritdoc cref=\"Math.Abs(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Abs(this Vector3 v) => new Vector3(Abs(v.x), Abs(v.y), Abs(v.z));\n\n        /// <inheritdoc cref=\"Math.Abs(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Abs(this Vector4 v) => new Vector4(Abs(v.x), Abs(v.y), Abs(v.z), Abs(v.w));\n\n        #endregion\n\n        #region Clamping\n\n        /// <summary>Returns the value clamped between <c>min</c> and <c>max</c></summary>\n        /// <param name=\"value\">The value to clamp</param>\n        /// <param name=\"min\">The minimum value</param>\n        /// <param name=\"max\">The maximum value</param>\n        public static float Clamp(this float value, float min, float max) =>\n            value < min ? min : value > max ? max : value;\n\n        /// <summary>Clamps each component between <c>min</c> and <c>max</c></summary>\n        public static Vector2 Clamp(this Vector2 v, Vector2 min, Vector2 max) =>\n            new Vector2(v.x < min.x ? min.x : v.x > max.x ? max.x : v.x,\n                v.y < min.y ? min.y : v.y > max.y ? max.y : v.y);\n\n        /// <inheritdoc cref=\"Math.Clamp(Vector2,Vector2,Vector2)\"/>\n        public static Vector3 Clamp(this Vector3 v, Vector3 min, Vector3 max) =>\n            new Vector3(v.x < min.x ? min.x : v.x > max.x ? max.x : v.x,\n                v.y < min.y ? min.y : v.y > max.y ? max.y : v.y,\n                v.z < min.z ? min.z : v.z > max.z ? max.z : v.z);\n\n        /// <inheritdoc cref=\"Math.Clamp(Vector2,Vector2,Vector2)\"/>\n        public static Vector4 Clamp(this Vector4 v, Vector4 min, Vector4 max) =>\n            new Vector4(v.x < min.x ? min.x : v.x > max.x ? max.x : v.x,\n                v.y < min.y ? min.y : v.y > max.y ? max.y : v.y,\n                v.z < min.z ? min.z : v.z > max.z ? max.z : v.z,\n                v.w < min.w ? min.w : v.w > max.w ? max.w : v.w);\n\n        /// <inheritdoc cref=\"Math.Clamp(float,float,float)\"/>\n        public static int Clamp(this int value, int min, int max) => value < min ? min : value > max ? max : value;\n\n        /// <summary>Returns the value clamped between 0 and 1</summary>\n        public static float Clamp01(this float value) => value < 0f ? 0f : value > 1f ? 1f : value;\n\n        /// <summary>Clamps each component between 0 and 1</summary>\n        public static Vector2 Clamp01(this Vector2 v) =>\n            new Vector2(v.x < 0f ? 0f : v.x > 1f ? 1f : v.x, v.y < 0f ? 0f : v.y > 1f ? 1f : v.y);\n\n        /// <inheritdoc cref=\"Math.Clamp01(Vector2)\"/>\n        public static Vector3 Clamp01(this Vector3 v) =>\n            new Vector3(v.x < 0f ? 0f : v.x > 1f ? 1f : v.x, v.y < 0f ? 0f : v.y > 1f ? 1f : v.y,\n                v.z < 0f ? 0f : v.z > 1f ? 1f : v.z);\n\n        /// <inheritdoc cref=\"Math.Clamp01(Vector2)\"/>\n        public static Vector4 Clamp01(this Vector4 v) =>\n            new Vector4(v.x < 0f ? 0f : v.x > 1f ? 1f : v.x,\n                v.y < 0f ? 0f : v.y > 1f ? 1f : v.y,\n                v.z < 0f ? 0f : v.z > 1f ? 1f : v.z,\n                v.w < 0f ? 0f : v.w > 1f ? 1f : v.w);\n\n        /// <summary>Clamps the value between -1 and 1</summary>\n        public static float ClampNeg1To1(this float value) => value < -1f ? -1f : value > 1f ? 1f : value;\n\n        /// <summary>Clamps each component between -1 and 1</summary>\n        public static Vector2 ClampNeg1To1(this Vector2 v) => new Vector2(v.x < -1f ? -1f : v.x > 1f ? 1f : v.x,\n            v.y < -1f ? -1f : v.y > 1f ? 1f : v.y);\n\n        /// <summary>Clamps each component between -1 and 1</summary>\n        public static Vector3 ClampNeg1To1(this Vector3 v) =>\n            new Vector3(v.x < -1f ? -1f : v.x > 1f ? 1f : v.x, v.y < -1f ? -1f : v.y > 1f ? 1f : v.y,\n                v.z < -1f ? -1f : v.z > 1f ? 1f : v.z);\n\n        /// <summary>Clamps each component between -1 and 1</summary>\n        public static Vector4 ClampNeg1To1(this Vector4 v) =>\n            new Vector4(v.x < -1f ? -1f : v.x > 1f ? 1f : v.x,\n                v.y < -1f ? -1f : v.y > 1f ? 1f : v.y,\n                v.z < -1f ? -1f : v.z > 1f ? 1f : v.z,\n                v.w < -1f ? -1f : v.w > 1f ? 1f : v.w);\n\n        #endregion\n\n        #region Min & Max\n\n        /// <summary>Returns the smallest of the two values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(this float a, float b) => a < b ? a : b;\n\n        /// <summary>Returns the smallest of the three values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(this float a, float b, float c) => Min(Min(a, b), c);\n\n        /// <summary>Returns the smallest of the four values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(this float a, float b, float c, float d) => Min(Min(a, b), Min(c, d));\n\n        /// <summary>Returns the largest of the two values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(this float a, float b) => a > b ? a : b;\n\n        /// <summary>Returns the largest of the three values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(this float a, float b, float c) => Max(Max(a, b), c);\n\n        /// <summary>Returns the largest of the four values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(this float a, float b, float c, float d) => Max(Max(a, b), Max(c, d));\n\n        /// <summary>Returns the smallest of the two values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Min(this int a, int b) => a < b ? a : b;\n\n        /// <summary>Returns the smallest of the three values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Min(this int a, int b, int c) => Min(Min(a, b), c);\n\n        /// <summary>Returns the smallest of the four values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Min(this int a, int b, int c, int d) => Min(Min(a, b), Min(c, d));\n\n        /// <summary>Returns the largest of the two values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Max(this int a, int b) => a > b ? a : b;\n\n        /// <summary>Returns the largest of the three values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Max(this int a, int b, int c) => Max(Max(a, b), c);\n\n        /// <summary>Returns the largest of the four values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Max(this int a, int b, int c, int d) => Max(Max(a, b), Max(c, d));\n\n        private static float MinCopyLinq(float[] source)\n        {\n            float r = float.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n                else if (float.IsNaN(source[i])) return source[i];\n            }\n\n            return r;\n        }\n\n        private static int MinCopyLinq(int[] source)\n        {\n            int r = int.MaxValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] < r) r = source[i];\n            }\n\n            return r;\n        }\n\n        private static int MaxCopyLinq(int[] source)\n        {\n            int r = int.MinValue;\n            for (int i = 0; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        private static float MaxCopyLinq(float[] source)\n        {\n            float r = source[0];\n            int startIndex = 0;\n            for (; startIndex < source.Length; startIndex++)\n            {\n                if (!float.IsNaN(source[startIndex]))\n                {\n                    r = source[startIndex];\n                    break;\n                }\n            }\n\n            for (int i = startIndex; i < source.Length; i++)\n            {\n                if (source[i] > r) r = source[i];\n            }\n\n            return r;\n        }\n\n        /// <summary>Returns the smallest of the given values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(params float[] values) => MinCopyLinq(values);\n\n        /// <summary>Returns the largest of the given values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(params float[] values) => MaxCopyLinq(values);\n\n        /// <summary>Returns the smallest of the given values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Min(params int[] values) => MinCopyLinq(values);\n\n        /// <summary>Returns the largest of the given values</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int Max(params int[] values) => MaxCopyLinq(values);\n\n        /// <summary>Returns the minimum value of all components in the vector</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(this Vector2 v) => Min(v.x, v.y);\n\n        /// <inheritdoc cref=\"Math.Min(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(this Vector3 v) => Min(v.x, v.y, v.z);\n\n        /// <inheritdoc cref=\"Math.Min(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Min(this Vector4 v) => Min(v.x, v.y, v.z, v.w);\n\n        /// <summary>Returns the maximum value of all components in the vector</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(this Vector2 v) => Max(v.x, v.y);\n\n        /// <inheritdoc cref=\"Math.Max(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(this Vector3 v) => Max(v.x, v.y, v.z);\n\n        /// <inheritdoc cref=\"Math.Max(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Max(this Vector4 v) => Max(v.x, v.y, v.z, v.w);\n\n        #endregion\n\n        #region Rounding\n\n        /// <summary>Rounds the value down to the nearest integer</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Floor(this float value) => (float)System.Math.Floor(value);\n\n        /// <summary>Rounds the vector components down to the nearest integer</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Floor(this Vector2 value) =>\n            new Vector2((float)System.Math.Floor(value.x), (float)System.Math.Floor(value.y));\n\n        /// <inheritdoc cref=\"Math.Floor(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Floor(this Vector3 value) =>\n            new Vector3((float)System.Math.Floor(value.x), (float)System.Math.Floor(value.y),\n                (float)System.Math.Floor(value.z));\n\n        /// <inheritdoc cref=\"Math.Floor(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Floor(this Vector4 value) =>\n            new Vector4((float)System.Math.Floor(value.x), (float)System.Math.Floor(value.y),\n                (float)System.Math.Floor(value.z), (float)System.Math.Floor(value.w));\n\n        /// <summary>Rounds the value down to the nearest integer, returning an int value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int FloorToInt(this float value) => (int)System.Math.Floor(value);\n\n        /// <summary>Rounds the vector components down to the nearest integer, returning an integer vector</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2Int FloorToInt(this Vector2 value) =>\n            new Vector2Int((int)System.Math.Floor(value.x), (int)System.Math.Floor(value.y));\n\n        /// <inheritdoc cref=\"Math.FloorToInt(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3Int FloorToInt(this Vector3 value) =>\n            new Vector3Int((int)System.Math.Floor(value.x), (int)System.Math.Floor(value.y),\n                (int)System.Math.Floor(value.z));\n\n        /// <summary>Rounds the value up to the nearest integer</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Ceil(this float value) => (float)System.Math.Ceiling(value);\n\n        /// <summary>Rounds the vector components up to the nearest integer</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Ceil(this Vector2 value) =>\n            new Vector2((float)System.Math.Ceiling(value.x), (float)System.Math.Ceiling(value.y));\n\n        /// <inheritdoc cref=\"Math.Ceil(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Ceil(this Vector3 value) =>\n            new Vector3((float)System.Math.Ceiling(value.x), (float)System.Math.Ceiling(value.y),\n                (float)System.Math.Ceiling(value.z));\n\n        /// <inheritdoc cref=\"Math.Ceil(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Ceil(this Vector4 value) =>\n            new Vector4((float)System.Math.Ceiling(value.x),\n                (float)System.Math.Ceiling(value.y),\n                (float)System.Math.Ceiling(value.z),\n                (float)System.Math.Ceiling(value.w));\n\n        /// <summary>Rounds the value up to the nearest integer, returning an int value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int CeilToInt(this float value) => (int)System.Math.Ceiling(value);\n\n        /// <summary>Rounds the vector components up to the nearest integer, returning an integer vector</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2Int CeilToInt(this Vector2 value) =>\n            new Vector2Int((int)System.Math.Ceiling(value.x), (int)System.Math.Ceiling(value.y));\n\n        /// <inheritdoc cref=\"Math.CeilToInt(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3Int CeilToInt(this Vector3 value) =>\n            new Vector3Int((int)System.Math.Ceiling(value.x), (int)System.Math.Ceiling(value.y),\n                (int)System.Math.Ceiling(value.z));\n\n        /// <summary>Rounds the value to the nearest integer</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Round(this float value) => (float)System.Math.Round(value);\n\n        /// <summary>Rounds the vector components to the nearest integer</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Round(this Vector2 value) =>\n            new Vector2((float)System.Math.Round(value.x), (float)System.Math.Round(value.y));\n\n        /// <inheritdoc cref=\"Math.Round(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Round(this Vector3 value) =>\n            new Vector3((float)System.Math.Round(value.x), (float)System.Math.Round(value.y),\n                (float)System.Math.Round(value.z));\n\n        /// <inheritdoc cref=\"Math.Round(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Round(this Vector4 value) =>\n            new Vector4((float)System.Math.Round(value.x), (float)System.Math.Round(value.y),\n                (float)System.Math.Round(value.z), (float)System.Math.Round(value.w));\n\n        /// <summary>Rounds the value to the nearest value, snapped to the given interval size</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Round(this float value, float snapInterval) =>\n            Mathf.Round(value / snapInterval) * snapInterval;\n\n        /// <summary>Rounds the vector components to the nearest value, snapped to the given interval size</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Round(this Vector2 value, float snapInterval) =>\n            new Vector2(Round(value.x, snapInterval), Round(value.y, snapInterval));\n\n        /// <inheritdoc cref=\"Math.Round(Vector2,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Round(this Vector3 value, float snapInterval) =>\n            new Vector3(Round(value.x, snapInterval), Round(value.y, snapInterval), Round(value.z, snapInterval));\n\n        /// <inheritdoc cref=\"Math.Round(Vector2,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Round(this Vector4 value, float snapInterval) =>\n            new Vector4(Round(value.x, snapInterval), Round(value.y, snapInterval), Round(value.z, snapInterval),\n                Round(value.w, snapInterval));\n\n        /// <summary>Rounds the value to the nearest integer, returning an int value</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static int RoundToInt(this float value) => (int)System.Math.Round(value);\n\n        /// <summary>Rounds the vector components to the nearest integer, returning an integer vector</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2Int RoundToInt(this Vector2 value) =>\n            new Vector2Int((int)System.Math.Round(value.x), (int)System.Math.Round(value.y));\n\n        /// <inheritdoc cref=\"Math.RoundToInt(Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3Int RoundToInt(this Vector3 value) =>\n            new Vector3Int((int)System.Math.Round(value.x), (int)System.Math.Round(value.y),\n                (int)System.Math.Round(value.z));\n\n        #endregion\n\n        #region Repeat\n\n        /// <summary>Repeats the given value in the interval specified by length</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Repeat(this float value, float length) =>\n            Clamp(value - Floor(value / length) * length, 0.0f, length);\n\n        /// <summary>Repeats a value within a range, going back and forth</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float PingPong(float t, float length) => length - Abs(Repeat(t, length * 2f) - length);\n\n        #endregion\n\n        #region Smoothing\n\n        /// <summary>Applies cubic smoothing to the 0-1 interval, also known as the smoothstep function. Similar to an EaseInOut operation</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Smooth01(float x) => x * x * (3 - 2 * x);\n\n        /// <summary>Applies quintic smoothing to the 0-1 interval, also known as the smootherstep function. Similar to an EaseInOut operation</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Smoother01(float x) => x * x * x * (x * (x * 6 - 15) + 10);\n\n        /// <summary>Applies trigonometric smoothing to the 0-1 interval. Similar to an EaseInOut operation</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float SmoothCos01(float x) => Cos(x * PI) * -0.5f + 0.5f;\n\n        /// <summary>Applies a gamma curve or something idk I've never used this function before but it was part of Unity's original M.cs and it's undocumented</summary>\n        public static float Gamma(float value, float absmax, float gamma)\n        {\n            bool negative = value < 0F;\n            float absval = Abs(value);\n            if (absval > absmax)\n                return negative ? -absval : absval;\n\n            float result = Pow(absval / absmax, gamma) * absmax;\n            return negative ? -result : result;\n        }\n\n        /// <summary>Gradually changes a value towards a desired goal over time.\n        /// The value is smoothed by some spring-damper like function, which will never overshoot.\n        /// The function can be used to smooth any kind of value, positions, colors, scalars</summary>\n        /// <param name=\"current\">The current position</param>\n        /// <param name=\"target\">The position we are trying to reach</param>\n        /// <param name=\"currentVelocity\">The current velocity, this value is modified by the function every time you call it</param>\n        /// <param name=\"smoothTime\">Approximately the time it will take to reach the target. A smaller value will reach the target faster</param>\n        /// <param name=\"maxSpeed\">\tOptionally allows you to clamp the maximum speed</param>\n        public static float SmoothDamp(float current, float target, ref float currentVelocity, float smoothTime,\n            float maxSpeed = Infinity)\n        {\n            float deltaTime = Time.deltaTime;\n            return SmoothDamp(current,\n                target,\n                ref currentVelocity,\n                smoothTime,\n                maxSpeed,\n                deltaTime);\n        }\n\n        /// <summary>Gradually changes a value towards a desired goal over time.\n        /// The value is smoothed by some spring-damper like function, which will never overshoot.\n        /// The function can be used to smooth any kind of value, positions, colors, scalars</summary>\n        /// <param name=\"current\">The current position</param>\n        /// <param name=\"target\">The position we are trying to reach</param>\n        /// <param name=\"currentVelocity\">The current velocity, this value is modified by the function every time you call it</param>\n        /// <param name=\"smoothTime\">Approximately the time it will take to reach the target. A smaller value will reach the target faster</param>\n        /// <param name=\"maxSpeed\">\tOptionally allows you to clamp the maximum speed</param>\n        /// <param name=\"deltaTime\">The time since the last call to this function. By default Time.deltaTime</param>\n        public static float SmoothDamp(\n            float current,\n            float target,\n            ref float currentVelocity,\n            float smoothTime,\n            [UnityEngine.Internal.DefaultValue(\"Mathf.Infinity\")]\n            float maxSpeed,\n            [UnityEngine.Internal.DefaultValue(\"Time.deltaTime\")]\n            float deltaTime)\n        {\n            // Based on Game Programming Gems 4 Chapter 1.10\n            smoothTime = Mathf.Max(0.0001F, smoothTime);\n            float omega = 2F / smoothTime;\n\n            float x = omega * deltaTime;\n            float exp = 1F / (1F + x + 0.48F * x * x + 0.235F * x * x * x);\n            float change = current - target;\n            float originalTo = target;\n\n            // Clamp maximum speed\n            float maxChange = maxSpeed * smoothTime;\n            change = Mathf.Clamp(change, -maxChange, maxChange);\n            target = current - change;\n\n            float temp = (currentVelocity + omega * change) * deltaTime;\n            currentVelocity = (currentVelocity - omega * temp) * exp;\n            float output = target + (change + temp) * exp;\n\n            // Prevent overshooting\n            if (originalTo - current > 0.0F == output > originalTo)\n            {\n                output = originalTo;\n                currentVelocity = (output - originalTo) / deltaTime;\n            }\n\n            return output;\n        }\n\n        #endregion\n\n        #region Value & Vector interpolation\n\n        /// <summary>Blends between a and b, based on the t-value. When t = 0 it returns a, when t = 1 it returns b, and any values between are blended linearly </summary>\n        /// <param name=\"a\">The start value, when t is 0</param>\n        /// <param name=\"b\">The start value, when t is 1</param>\n        /// <param name=\"t\">The t-value from 0 to 1 representing position along the lerp</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Lerp(float a, float b, float t) => (1f - t) * a + t * b;\n\n        /// <summary>Blends between a and b of each component, based on the t-value of each component in the t-vector. When t = 0 it returns a, when t = 1 it returns b, and any values between are blended linearly </summary>\n        /// <param name=\"a\">The start value, when t is 0</param>\n        /// <param name=\"b\">The start value, when t is 1</param>\n        /// <param name=\"t\">The t-values from 0 to 1 representing position along the lerp</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Lerp(Vector2 a, Vector2 b, Vector2 t) =>\n            new Vector2(Lerp(a.x, b.x, t.x), Lerp(a.y, b.y, t.y));\n\n        /// <inheritdoc cref=\"Math.Lerp(Vector2,Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Lerp(Vector3 a, Vector3 b, Vector3 t) =>\n            new Vector3(Lerp(a.x, b.x, t.x), Lerp(a.y, b.y, t.y), Lerp(a.z, b.z, t.z));\n\n        /// <inheritdoc cref=\"Math.Lerp(Vector2,Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Lerp(Vector4 a, Vector4 b, Vector4 t) => new Vector4(Lerp(a.x, b.x, t.x),\n            Lerp(a.y, b.y, t.y), Lerp(a.z, b.z, t.z), Lerp(a.w, b.w, t.w));\n\n        /// <summary>Linearly blends between two rectangles, moving and resizing from the center. Note: this lerp is unclamped</summary>\n        /// <param name=\"a\">The start value, when t is 0</param>\n        /// <param name=\"b\">The start value, when t is 1</param>\n        /// <param name=\"t\">The t-values from 0 to 1 representing position along the lerp</param>\n        public static Rect Lerp(Rect a, Rect b, float t)\n        {\n            Vector2 center = Vector2.LerpUnclamped(a.center, b.center, t);\n            Vector2 size = Vector2.LerpUnclamped(a.size, b.size, t);\n            return new Rect(default, size) { center = center };\n        }\n\n        /// <summary>Blends between a and b, based on the t-value. When t = 0 it returns a, when t = 1 it returns b, and any values between are blended linearly</summary>\n        /// <param name=\"a\">The start value, when t is 0</param>\n        /// <param name=\"b\">The start value, when t is 1</param>\n        /// <param name=\"t\">The t-value from 0 to 1 representing position along the lerp, clamped between 0 and 1</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float LerpClamped(float a, float b, float t) => Lerp(a, b, Clamp01(t));\n\n        /// <summary>Lerps between a and b, applying cubic smoothing to the t-value</summary>\n        /// <param name=\"a\">The start value, when t is 0</param>\n        /// <param name=\"b\">The start value, when t is 1</param>\n        /// <param name=\"t\">The t-value from 0 to 1 representing position along the lerp, clamped between 0 and 1</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float LerpSmooth(float a, float b, float t) => Lerp(a, b, Smooth01(Clamp01(t)));\n\n        /// <summary>Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1</summary>\n        /// <param name=\"a\">The start of the range, where it would return 0</param>\n        /// <param name=\"b\">The end of the range, where it would return 1</param>\n        /// <param name=\"value\">A value between a and b. Note: values outside this range are still valid, and will be extrapolated</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float InverseLerp(float a, float b, float value) => (value - a) / (b - a);\n\n        /// <summary>Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1.\n        /// This safe version returns 0 if a == b, instead of a division by zero</summary>\n        /// <param name=\"a\">The start of the range, where it would return 0</param>\n        /// <param name=\"b\">The end of the range, where it would return 1</param>\n        /// <param name=\"value\">A value between a and b. Note: values outside this range are still valid, and will be extrapolated</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float InverseLerpSafe(float a, float b, float value)\n        {\n            float den = b - a;\n            if (den == 0)\n                return 0;\n            return (value - a) / den;\n        }\n\n        /// <summary>Given values between a and b in each component, returns their normalized locations in the given ranges, as t-values (interpolants) from 0 to 1</summary>\n        /// <param name=\"a\">The start of the ranges, where it would return 0</param>\n        /// <param name=\"b\">The end of the ranges, where it would return 1</param>\n        /// <param name=\"v\">A value between a and b. Note: values outside this range are still valid, and will be extrapolated</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 InverseLerp(Vector2 a, Vector2 b, Vector2 v) =>\n            new Vector2((v.x - a.x) / (b.x - a.x), (v.y - a.y) / (b.y - a.y));\n\n        /// <inheritdoc cref=\"Math.InverseLerp(Vector2,Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 InverseLerp(Vector3 a, Vector3 b, Vector3 v) =>\n            new Vector3((v.x - a.x) / (b.x - a.x), (v.y - a.y) / (b.y - a.y), (v.z - a.z) / (b.z - a.z));\n\n        /// <inheritdoc cref=\"Math.InverseLerp(Vector2,Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 InverseLerp(Vector4 a, Vector4 b, Vector4 v) =>\n            new Vector4((v.x - a.x) / (b.x - a.x), (v.y - a.y) / (b.y - a.y), (v.z - a.z) / (b.z - a.z),\n                (v.w - a.w) / (b.w - a.w));\n\n        /// <summary>Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) clamped between 0 and 1</summary>\n        /// <param name=\"a\">The start of the range, where it would return 0</param>\n        /// <param name=\"b\">The end of the range, where it would return 1</param>\n        /// <param name=\"value\">A value between a and b</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float InverseLerpClamped(float a, float b, float value) => Clamp01((value - a) / (b - a));\n\n        /// <summary>Given a value between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1, with cubic smoothing applied.\n        /// Equivalent to \"smoothstep\" in shader code</summary>\n        /// <param name=\"a\">The start of the range, where it would return 0</param>\n        /// <param name=\"b\">The end of the range, where it would return 1</param>\n        /// <param name=\"value\">A value between a and b. Note: values outside this range are still valid, and will be extrapolated</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float InverseLerpSmooth(float a, float b, float value) =>\n            Smooth01(Clamp01((value - a) / (b - a)));\n\n        /// <summary>Remaps a value from the input range [iMin to iMax] into the output range [oMin to oMax].\n        /// Equivalent to Lerp(oMin,oMax,InverseLerp(iMin,iMax,value))</summary>\n        /// <param name=\"iMin\">The start value of the input range</param>\n        /// <param name=\"iMax\">The end value of the input range</param>\n        /// <param name=\"oMin\">The start value of the output range</param>\n        /// <param name=\"oMax\">The end value of the output range</param>\n        /// <param name=\"value\">The value to remap</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Remap(float iMin, float iMax, float oMin, float oMax, float value) =>\n            Lerp(oMin, oMax, InverseLerp(iMin, iMax, value));\n\n        /// <inheritdoc cref=\"Math.Remap(float,float,float,float,float)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Remap(float iMin, float iMax, float oMin, float oMax, int value) =>\n            Lerp(oMin, oMax, InverseLerp(iMin, iMax, value));\n\n        /// <summary>Remaps values from the input range [iMin to iMax] into the output range [oMin to oMax] on a per-component basis.\n        /// Equivalent to Lerp(oMin,oMax,InverseLerp(iMin,iMax,value))</summary>\n        /// <param name=\"iMin\">The start values of the input ranges</param>\n        /// <param name=\"iMax\">The end values of the input ranges</param>\n        /// <param name=\"oMin\">The start values of the output ranges</param>\n        /// <param name=\"oMax\">The end values of the output ranges</param>\n        /// <param name=\"value\">The values to remap</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Remap(Vector2 iMin, Vector2 iMax, Vector2 oMin, Vector2 oMax, Vector2 value) =>\n            Lerp(oMin, oMax, InverseLerp(iMin, iMax, value));\n\n        /// <inheritdoc cref=\"Math.Remap(Vector2,Vector2,Vector2,Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Remap(Vector3 iMin, Vector3 iMax, Vector3 oMin, Vector3 oMax, Vector3 value) =>\n            Lerp(oMin, oMax, InverseLerp(iMin, iMax, value));\n\n        /// <inheritdoc cref=\"Math.Remap(Vector2,Vector2,Vector2,Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector4 Remap(Vector4 iMin, Vector4 iMax, Vector4 oMin, Vector4 oMax, Vector4 value) =>\n            Lerp(oMin, oMax, InverseLerp(iMin, iMax, value));\n\n        /// <summary>Remaps a value from the input range [iMin to iMax] into the output range [oMin to oMax], clamping to make sure it does not extrapolate.\n        /// Equivalent to Lerp(oMin,oMax,InverseLerpClamped(iMin,iMax,value))</summary>\n        /// <param name=\"iMin\">The start value of the input range</param>\n        /// <param name=\"iMax\">The end value of the input range</param>\n        /// <param name=\"oMin\">The start value of the output range</param>\n        /// <param name=\"oMax\">The end value of the output range</param>\n        /// <param name=\"value\">The value to remap</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float RemapClamped(float iMin, float iMax, float oMin, float oMax, float value) =>\n            Lerp(oMin, oMax, InverseLerpClamped(iMin, iMax, value));\n\n        /// <summary>Remaps a value from the input Rect to the output Rect</summary>\n        /// <param name=\"iRect\">The input Rect</param>\n        /// <param name=\"oRect\">The output Rect</param>\n        /// <param name=\"iPos\">The input position in the input Rect space</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector2 Remap(Rect iRect, Rect oRect, Vector2 iPos) =>\n            Remap(iRect.min,\n                iRect.max,\n                oRect.min,\n                oRect.max,\n                iPos);\n\n        /// <summary>Remaps a value from the input Bounds to the output Bounds</summary>\n        /// <param name=\"iBounds\">The input Bounds</param>\n        /// <param name=\"oBounds\">The output Bounds</param>\n        /// <param name=\"iPos\">The input position in the input Bounds space</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static Vector3 Remap(Bounds iBounds, Bounds oBounds, Vector3 iPos) =>\n            Remap(iBounds.min,\n                iBounds.max,\n                oBounds.min,\n                oBounds.max,\n                iPos);\n\n        /// <summary>Exponential interpolation, the multiplicative version of lerp, useful for values such as scaling or zooming</summary>\n        /// <param name=\"a\">The start value</param>\n        /// <param name=\"b\">The end value</param>\n        /// <param name=\"t\">The t-value from 0 to 1 representing position along the eerp</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Eerp(float a, float b, float t) => Mathf.Pow(a, 1 - t) * Mathf.Pow(b, t);\n\n        /// <summary>Inverse exponential interpolation, the multiplicative version of InverseLerp, useful for values such as scaling or zooming</summary>\n        /// <param name=\"a\">The start value</param>\n        /// <param name=\"b\">The end value</param>\n        /// <param name=\"v\">A value between a and b. Note: values outside this range are still valid, and will be extrapolated</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float InverseEerp(float a, float b, float v) => Mathf.Log(a / v) / Mathf.Log(a / b);\n\n        #endregion\n\n        #region Angle\n\n        /// <summary>Returns the angle of this vector, in radians</summary>\n        /// <param name=\"v\">The vector to get the angle of. It does not have to be normalized</param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Angle(this Vector2 v) => Mathf.Atan2(v.y, v.x);\n\n        /// <summary>Get the angle in degrees off the forward defined by x.</summary>\n        /// <param name=\"x\"></param>\n        /// <param name=\"y\"></param>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float Angle(this float x, float y) => Mathf.Atan2(y, x);\n\n        public static Vector2 Reflect(this Vector2 v, Vector2 normal)\n        {\n            var dp = 2 * Vector2.Dot(v, normal);\n            return new Vector2(v.x - normal.x * dp, v.y - normal.y * dp);\n        }\n\n        public static void Mirror(this ref Vector2 v, Vector2 axis)\n        {\n            v = (2 * (Vector2.Dot(v, axis) / Vector2.Dot(axis, axis)) * axis) - v;\n        }\n\n        public static Vector2 Mirror(this Vector2 v, Vector2 axis)\n        {\n            return (2 * (Vector2.Dot(v, axis) / Vector2.Dot(axis, axis)) * axis) - v;\n        }\n\n        /// <summary>\n        /// Angular interpolates between two vectors.\n        /// </summary>\n        /// <param name=\"from\"></param>\n        /// <param name=\"to\"></param>\n        /// <param name=\"t\"></param>\n        /// <returns>The vectors are 2 dimensional, so technically this is not a spherical linear interpolation. The name Slerp is kept for consistency. \n        /// The result would be if you Slerped between 2 Vector3's that had a z value of 0. The direction interpolates at an angular rate, where as the \n        /// magnitude interpolates at a linear rate.</returns>\n        public static Vector2 Slerp(this Vector2 from, Vector2 to, float t)\n        {\n            var a = NormalizeAngle(Lerp(Atan2(from.y, from.x), Atan2(to.y, to.x), t), true);\n            var l = Mathf.LerpUnclamped(from.magnitude, to.magnitude, t);\n            return new Vector2(Cos(a) * l, Sin(a) * l);\n        }\n\n        /// <summary>\n        /// Angular interpolates between two vectors.\n        /// </summary>\n        /// <param name=\"from\"></param>\n        /// <param name=\"to\"></param>\n        /// <param name=\"t\"></param>\n        /// <returns>The vectors are 2 dimensional, so technically this is not a spherical linear interpolation. The name Slerp is kept for consistency. \n        /// The result would be if you Slerped between 2 Vector3's that had a z value of 0. The direction interpolates at an angular rate, where as the \n        /// magnitude interpolates at a linear rate.</returns>\n        public static Vector2 SlerpClamped(this Vector2 from, Vector2 to, float t)\n        {\n            var a = NormalizeAngle(Lerp(Atan2(from.y, from.x), Atan2(to.y, to.x), t), true);\n            var l = Lerp(from.magnitude, to.magnitude, t);\n            return new Vector2(Cos(a) * l, Sin(a) * l);\n        }\n\n        /// <summary>Returns the shortest angle between <c>a</c> and <c>b</c>, in the range 0 to tau/2 (0 to pi)</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float AngleBetween(this Vector2 a, Vector2 b) =>\n            Mathf.Acos(Vector2.Dot(a.normalized, b.normalized).ClampNeg1To1());\n\n        /// <inheritdoc cref=\"AngleBetween(Vector2,Vector2)\"/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float AngleBetween(this Vector3 a, Vector3 b) =>\n            Mathf.Acos(Vector3.Dot(a.normalized, b.normalized).ClampNeg1To1());\n\n        /// <summary>\n        /// set an angle with in the bounds of -PI to PI\n        /// </summary>\n        /// <param name=\"angle\"></param>\n        /// <param name=\"useRadians\"></param>\n        /// <returns></returns>\n        /// <remarks></remarks>\n        public static float NormalizeAngle(this float angle, bool useRadians = true)\n        {\n            float rd = (useRadians ? PI : 180);\n            return Wrap(angle, rd, -rd);\n        }\n\n        public static float ClampIn180(this float a, bool bUseRadians = false)\n        {\n            return NormalizeAngle(a, bUseRadians);\n        }\n\n        public static float ClampIn360(this float a, bool bUseRadians = false)\n        {\n            a = NormalizeAngle(a, bUseRadians);\n            if (a < 0f) a += (bUseRadians) ? TWO_PI : 360.0f;\n            return a;\n        }\n\n        /// <summary>Blends between the <c>aRad</c> and <c>bRad</c> angles, based on the input t-value between 0 and 1</summary>\n        /// <param name=\"aRad\">The start value, in radians</param>\n        /// <param name=\"bRad\">The end value, in radians</param>\n        /// <param name=\"t\">The t-value between 0 and 1</param>\n        public static float LerpAngle(this float aRad, float bRad, float t)\n        {\n            float delta = Repeat((bRad - aRad), TWO_PI);\n            if (delta > PI)\n                delta -= TWO_PI;\n            return aRad + delta * Clamp01(t);\n        }\n\n        /// <summary>Returns the shortest angle between the two input angles, in radians</summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static float DeltaAngle(this float a, float b) => (b - a + PI).Repeat(TWO_PI) - PI;\n\n        /// <summary>Given an angle between a and b, returns its normalized location in that range, as a t-value (interpolant) from 0 to 1</summary>\n        /// <param name=\"a\">The start angle of the range (in radians), where it would return 0</param>\n        /// <param name=\"b\">The end angle of the range (in radians), where it would return 1</param>\n        /// <param name=\"v\">An angle between a and b</param>\n        public static float InverseLerpAngle(this float a, float b, float v)\n        {\n            float angBetween = DeltaAngle(a, b);\n            b = a + angBetween; // removes any a->b discontinuity\n            float h = a + angBetween * 0.5f; // halfway angle\n            v = h + DeltaAngle(h, v); // get offset from h, and offset by h\n            return InverseLerpClamped(a, b, v);\n        }\n\n        /// <summary>Gradually changes an angle given in radians towards a desired goal angle over time.\n        /// The value is smoothed by some spring-damper like function.\n        /// The function can be used to smooth any kind of value, positions, colors, scalars. The most common use is for smoothing a follow camera.</summary>\n        /// <param name=\"current\">The current angle</param>\n        /// <param name=\"target\">The angle we are trying to reach</param>\n        /// <param name=\"currentVelocity\">The current angular velocity, this value is modified by the function every time you call it</param>\n        /// <param name=\"smoothTime\">Approximately the time it will take to reach the target. A smaller value will reach the target faster</param>\n        /// <param name=\"maxSpeed\">Optionally allows you to clamp the maximum speed</param>\n        public static float SmoothDampAngle(this float current, float target, ref float currentVelocity,\n            float smoothTime, float maxSpeed = Infinity)\n        {\n            float deltaTime = Time.deltaTime;\n            return SmoothDampAngle(current,\n                target,\n                ref currentVelocity,\n                smoothTime,\n                maxSpeed,\n                deltaTime);\n        }\n\n        /// <summary>Gradually changes an angle given in radians towards a desired goal angle over time.\n        /// The value is smoothed by some spring-damper like function.\n        /// The function can be used to smooth any kind of value, positions, colors, scalars. The most common use is for smoothing a follow camera.</summary>\n        /// <param name=\"current\">The current angle</param>\n        /// <param name=\"target\">The angle we are trying to reach</param>\n        /// <param name=\"currentVelocity\">The current angular velocity, this value is modified by the function every time you call it</param>\n        /// <param name=\"smoothTime\">Approximately the time it will take to reach the target. A smaller value will reach the target faster</param>\n        /// <param name=\"maxSpeed\">Optionally allows you to clamp the maximum speed</param>\n        /// <param name=\"deltaTime\">The time since the last call to this function. By default Time.deltaTime</param>\n        public static float SmoothDampAngle(\n            this float current,\n            float target,\n            ref float currentVelocity,\n            float smoothTime,\n            [UnityEngine.Internal.DefaultValue(\"Mathf.Infinity\")]\n            float maxSpeed,\n            [UnityEngine.Internal.DefaultValue(\"Time.deltaTime\")]\n            float deltaTime)\n        {\n            target = current + DeltaAngle(current, target);\n            return SmoothDamp(current,\n                target,\n                ref currentVelocity,\n                smoothTime,\n                maxSpeed,\n                deltaTime);\n        }\n\n        #endregion\n\n        #region Wrap\n\n        public enum WrapMode\n        {\n            Oblivion = 0,\n            Clamp = 1,\n            Loop = 2,\n            PingPong = 3\n        }\n\n        /// <summary>\n        /// Wraps a value around some significant range.\n        /// \n        /// Similar to C# modulo, but works like a true module, in a unary direction over any range (including negative values).\n        /// \n        /// ex:\n        /// Wrap(8,6,2) == 4\n        /// Wrap(4,2,0) == 0\n        /// Wrap(4,2,-2) == 0\n        /// </summary>\n        /// <param name=\"value\">value to wrap</param>\n        /// <param name=\"max\">max in range</param>\n        /// <param name=\"min\">min in range</param>\n        /// <returns>A value wrapped around min to max</returns>\n        /// <remarks></remarks>\n        public static int Wrap(this int value, int max, int min)\n        {\n            max -= min;\n            if (max == 0)\n                return min;\n\n            var result = (value - min) % max;\n            return result < 0 ? result + max + min : result + min;\n        }\n\n        public static int Wrap(this int value, int max)\n        {\n            var result = value % max;\n            return result < 0 ? result + max : result;\n        }\n\n        public static long Wrap(this long value, long max, long min)\n        {\n            max -= min;\n            if (max == 0)\n                return min;\n\n            var result = (value - min) % max;\n            return result < 0 ? result + max + min : result + min;\n        }\n\n        public static long Wrap(long value, long max)\n        {\n            var result = value % max;\n            return result < 0 ? result + max : result;\n        }\n\n        public static float Wrap(this float value, float max, float min)\n        {\n            max -= min;\n            if (max == 0)\n                return min;\n\n            var result = (value - min) % max;\n            return result < 0 ? result + max + min : result + min;\n        }\n\n        public static float Wrap(this float value, float max)\n        {\n            var result = value % max;\n            return result < 0 ? result + max : result;\n        }\n\n        public static double Wrap(this double value, double max, double min)\n        {\n            max -= min;\n            if (max == 0)\n                return min;\n\n            var result = (value - min) % max;\n            return result < 0 ? result + max + min : result + min;\n        }\n\n        public static double Wrap(this double value, double max)\n        {\n            var result = value % max;\n            return result < 0 ? result + max : result;\n        }\n\n        /// <summary>\n        /// Wrap an index by some mode\n        /// </summary>\n        /// <param name=\"mode\"></param>\n        /// <param name=\"value\"></param>\n        /// <param name=\"max\"></param>\n        /// <returns></returns>\n        public static int WrapIndex(WrapMode mode, int value, int max)\n        {\n            switch (mode)\n            {\n                case WrapMode.Clamp:\n                    return Clamp(value, 0, max - 1);\n                case WrapMode.Loop:\n                    return Wrap(value, max);\n                case WrapMode.PingPong:\n                    return (int)PingPong(value, max - 1);\n                default:\n                    return value;\n            }\n        }\n\n        public static float Wrap(WrapMode mode, int value, int max, int min = 0)\n        {\n            switch (mode)\n            {\n                case WrapMode.Clamp:\n                    return Clamp(value, min, max);\n                case WrapMode.Loop:\n                    return Wrap(value, max, min);\n                case WrapMode.PingPong:\n                    return (int)PingPong(value - min, max - min) + min;\n                default:\n                    return value;\n            }\n        }\n\n        public static float Wrap(WrapMode mode, float value, float max, float min = 0)\n        {\n            switch (mode)\n            {\n                case WrapMode.Clamp:\n                    return Clamp(value, min, max - 1);\n                case WrapMode.Loop:\n                    return Wrap(value, max, min);\n                case WrapMode.PingPong:\n                    return (int)PingPong(value - min, max - min - 1) + min;\n                default:\n                    return value;\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Math.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f897424e6b154873aff43970d12790bb\ntimeCreated: 1723799321"
  },
  {
    "path": "VirtueSky/Misc/Common.Physics.cs",
    "content": "﻿using System.Collections.Generic;\nusing UnityEngine;\n\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        #region IgnoreCollision\n\n        public static void IgnoreCollision(List<Collider> _listCollider, Collider _collider)\n        {\n            _listCollider.ForEach(col => { Physics.IgnoreCollision(col, _collider); });\n        }\n\n        public static void IgnoreCollision(Collider _collider, List<Collider> _listCollider)\n        {\n            _listCollider.ForEach(col => { Physics.IgnoreCollision(col, _collider); });\n        }\n\n        public static void IgnoreCollision(List<Collider> _listCollider1, List<Collider> _listCollider2)\n        {\n            foreach (var VARIABLE1 in _listCollider1)\n            {\n                foreach (var VARIABLE2 in _listCollider2)\n                {\n                    Physics.IgnoreCollision(VARIABLE1, VARIABLE2);\n                }\n            }\n        }\n\n        public static void IgnoreCollision2D(List<Collider2D> _listCollider, Collider2D _collider)\n        {\n            foreach (var VARIABLE in _listCollider)\n            {\n                Physics2D.IgnoreCollision(VARIABLE, _collider);\n            }\n        }\n\n        public static void IgnoreCollision2D(Collider2D _collider, List<Collider2D> _listCollider)\n        {\n            foreach (var VARIABLE in _listCollider)\n            {\n                Physics2D.IgnoreCollision(VARIABLE, _collider);\n            }\n        }\n\n        public static void IgnoreCollision2D(List<Collider2D> _listCollider1, List<Collider2D> _listCollider2)\n        {\n            foreach (var VARIABLE1 in _listCollider1)\n            {\n                foreach (var VARIABLE2 in _listCollider2)\n                {\n                    Physics2D.IgnoreCollision(VARIABLE1, VARIABLE2);\n                }\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Physics.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f8f668bda2394a7eb6ee3d51ce842d1a\ntimeCreated: 1699243844"
  },
  {
    "path": "VirtueSky/Misc/Common.SkeletonAnimation.cs",
    "content": "using System;\nusing System.Collections.Generic;\n#if VIRTUESKY_SKELETON\nusing Spine;\nusing Spine.Unity;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing Animation = Spine.Animation;\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        public static float Duration(this SkeletonAnimation skeletonAnimation, string animationName)\n        {\n            Animation animation = null;\n            foreach (var animationsItem in skeletonAnimation.AnimationState.Data.SkeletonData.Animations.Items)\n            {\n                if (animationsItem.Name.Equals(animationName))\n                {\n                    animation = animationsItem;\n                    break;\n                }\n            }\n\n            if (animation == null) return 0;\n            return animation.Duration;\n        }\n\n        public static float Duration(this SkeletonAnimation skeletonAnimation, int track = 0)\n        {\n            var animation = skeletonAnimation.AnimationState.GetCurrent(track);\n            if (animation == null) return 0;\n            return animation.Animation.Duration;\n        }\n\n        public static SkeletonAnimation OnComplete(this SkeletonAnimation skeletonAnimation, Action onComplete,\n            int trackIndex = 0, MonoBehaviour target = null)\n        {\n            App.Delay(target != null ? target : skeletonAnimation, skeletonAnimation.Duration(trackIndex), () =>\n            {\n                if (skeletonAnimation != null)\n                {\n                    onComplete?.Invoke();\n                }\n            });\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation OnUpdate(this SkeletonAnimation skeletonAnimation, Action<float> onUpdate,\n            int trackIndex = 0, MonoBehaviour target = null)\n        {\n            App.Delay(target != null ? target : skeletonAnimation, skeletonAnimation.Duration(trackIndex), null,\n                onUpdate);\n            return skeletonAnimation;\n        }\n\n        public static TrackEntry OnComplete(this TrackEntry trackEntry, Action onComplete)\n        {\n            trackEntry.Complete += HandleComplete;\n\n            void HandleComplete(TrackEntry track)\n            {\n                trackEntry.Complete -= HandleComplete;\n                onComplete?.Invoke();\n            }\n\n            return trackEntry;\n        }\n\n\n        public static SkeletonAnimation Play(this SkeletonAnimation skeletonAnimation, string animationName,\n            bool loop = false, int trackIndex = 0, float timeScale = 1f)\n        {\n            skeletonAnimation.ClearState();\n            skeletonAnimation.AnimationName = animationName;\n            skeletonAnimation.loop = loop;\n            var trackEntry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationName, loop);\n            trackEntry.TimeScale = timeScale;\n            skeletonAnimation.LateUpdate();\n            skeletonAnimation.Initialize(true);\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation PlayOnly(this SkeletonAnimation skeletonAnimation, string animationName,\n            bool loop = false, int trackIndex = 0, float timeScale = 1f)\n        {\n            skeletonAnimation.AnimationName = animationName;\n            var trackEntry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationName, loop);\n            trackEntry.TimeScale = timeScale;\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation AddAnimation(this SkeletonAnimation skeletonAnimation, int trackIndex,\n            string animationName, bool loop, float timeDelay = 0f, float mixDuration = 0f, float timeScale = 1f)\n        {\n            var track = skeletonAnimation.AnimationState.AddAnimation(trackIndex, animationName, loop, timeDelay);\n            track.MixDuration = mixDuration;\n            track.TimeScale = timeScale;\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation SetSkin(this SkeletonAnimation skeletonAnimation, string skinName)\n        {\n            var skin = new Skin(\"temp\");\n            skin.AddSkin(skeletonAnimation.skeleton.Data.FindSkin(skinName));\n            skeletonAnimation.initialSkinName = \"temp\";\n            skeletonAnimation.skeleton.SetSkin(skin);\n            skeletonAnimation.skeleton.SetSlotsToSetupPose();\n            skeletonAnimation.LateUpdate();\n            skeletonAnimation.AnimationState.Apply(skeletonAnimation.skeleton);\n\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation SetSkin(this SkeletonAnimation skeletonAnimation, List<string> skinNames)\n        {\n            var skin = new Skin(\"temp\");\n            var skeletonData = skeletonAnimation.Skeleton.Data;\n            foreach (string skinName in skinNames)\n            {\n                skin.AddSkin(skeletonData.FindSkin(skinName));\n            }\n\n            skeletonAnimation.initialSkinName = \"temp\";\n            skeletonAnimation.skeleton.SetSkin(skin);\n            skeletonAnimation.skeleton.SetSlotsToSetupPose();\n            skeletonAnimation.LateUpdate();\n            skeletonAnimation.AnimationState.Apply(skeletonAnimation.skeleton);\n\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation ChangeAttachment(this SkeletonAnimation skeletonAnimation, string slotName,\n            string attachmentName)\n        {\n            var slotIndex = skeletonAnimation.skeleton.Data.FindSlot(slotName).Index;\n            var attachment = skeletonAnimation.skeleton.GetAttachment(slotIndex, attachmentName);\n            var skin = new Skin(\"temp\");\n            skin.SetAttachment(slotIndex, slotName, attachment);\n            skeletonAnimation.skeleton.SetSkin(skin);\n            skeletonAnimation.skeleton.SetSlotsToSetupPose();\n            skeletonAnimation.LateUpdate();\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation ChangeAttachment(this SkeletonAnimation skeletonAnimation, string slotName,\n            List<string> attachmentNames)\n        {\n            var slotIndex = skeletonAnimation.skeleton.Data.FindSlot(slotName).Index;\n            var skin = new Skin(\"temp\");\n            foreach (var attachmentName in attachmentNames)\n            {\n                var attachment = skeletonAnimation.skeleton.GetAttachment(slotIndex, attachmentName);\n                skin.SetAttachment(slotIndex, slotName, attachment);\n            }\n\n            skeletonAnimation.skeleton.SetSkin(skin);\n            skeletonAnimation.skeleton.SetSlotsToSetupPose();\n            skeletonAnimation.LateUpdate();\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation MixSkin(this SkeletonAnimation skeletonAnimation, string mixSkinName)\n        {\n            Skin skin = new Skin(\"temp\");\n            skin.AddSkin(skeletonAnimation.Skeleton.Data.FindSkin(mixSkinName));\n            skeletonAnimation.Skeleton.SetSkin(skin);\n            skeletonAnimation.Skeleton.SetSlotsToSetupPose();\n            skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);\n            return skeletonAnimation;\n        }\n\n        public static SkeletonAnimation MixSkin(this SkeletonAnimation skeletonAnimation, List<string> mixSkinNames)\n        {\n            Skin skin = new Skin(\"temp\");\n            foreach (var mixSkinName in mixSkinNames)\n            {\n                skin.AddSkin(skeletonAnimation.Skeleton.Data.FindSkin(mixSkinName));\n            }\n\n            skeletonAnimation.Skeleton.SetSkin(skin);\n            skeletonAnimation.Skeleton.SetSlotsToSetupPose();\n            skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);\n            return skeletonAnimation;\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "VirtueSky/Misc/Common.SkeletonAnimation.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f264a02e80144c4d8eb55c2064ab5032\ntimeCreated: 1708065730"
  },
  {
    "path": "VirtueSky/Misc/Common.SkeletonGraphic.cs",
    "content": "using System;\nusing System.Collections.Generic;\n#if VIRTUESKY_SKELETON\nusing Spine;\nusing Spine.Unity;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing Animation = Spine.Animation;\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        public static float Duration(this SkeletonGraphic skeletonGraphic, string animationName)\n        {\n            Animation animation = null;\n            foreach (var animationsItem in skeletonGraphic.AnimationState.Data.SkeletonData.Animations.Items)\n            {\n                if (animationsItem.Name.Equals(animationName))\n                {\n                    animation = animationsItem;\n                    break;\n                }\n            }\n\n            if (animation == null) return 0;\n            return animation.Duration;\n        }\n\n        public static float Duration(this SkeletonGraphic skeletonGraphic, int track = 0)\n        {\n            var animation = skeletonGraphic.AnimationState.GetCurrent(track);\n            if (animation == null) return 0;\n            return animation.Animation.Duration;\n        }\n\n        public static SkeletonGraphic OnComplete(this SkeletonGraphic skeletonGraphic, Action onComplete,\n            int trackIndex = 0, MonoBehaviour target = null)\n        {\n            App.Delay(target != null ? target : skeletonGraphic, skeletonGraphic.Duration(trackIndex), () =>\n            {\n                if (skeletonGraphic != null)\n                {\n                    onComplete?.Invoke();\n                }\n            });\n            return skeletonGraphic;\n        }\n\n\n        public static SkeletonGraphic OnUpdate(this SkeletonGraphic skeletonGraphic, Action<float> onUpdate,\n            int trackIndex = 0, MonoBehaviour target = null)\n        {\n            App.Delay(target != null ? target : skeletonGraphic, skeletonGraphic.Duration(trackIndex), null, onUpdate);\n            return skeletonGraphic;\n        }\n\n\n        public static SkeletonGraphic Play(this SkeletonGraphic skeletonGraphic, string animationName,\n            bool loop = false, int trackIndex = 0, float timeScale = 1f)\n        {\n            skeletonGraphic.Clear();\n            skeletonGraphic.startingAnimation = animationName;\n            skeletonGraphic.startingLoop = loop;\n            var trackEntry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animationName, loop);\n            trackEntry.TimeScale = timeScale;\n            skeletonGraphic.LateUpdate();\n            skeletonGraphic.Initialize(true);\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic PlayOnly(this SkeletonGraphic skeletonGraphic, string animationName,\n            bool loop = false, int trackIndex = 0, float timeScale = 1f)\n        {\n            skeletonGraphic.startingAnimation = animationName;\n            var trackEntry = skeletonGraphic.AnimationState.SetAnimation(trackIndex, animationName, loop);\n            trackEntry.TimeScale = timeScale;\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic AddAnimation(this SkeletonGraphic skeletonGraphic, int trackIndex,\n            string animationName, bool loop, float timeDelay = 0f, float mixDuration = 0f, float timeScale = 1f)\n        {\n            var track = skeletonGraphic.AnimationState.AddAnimation(trackIndex, animationName, loop, timeDelay);\n            track.MixDuration = mixDuration;\n            track.TimeScale = timeScale;\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic SetSkin(this SkeletonGraphic skeletonGraphic, string skinName)\n        {\n            var skin = new Skin(\"temp\");\n            skin.AddSkin(skeletonGraphic.Skeleton.Data.FindSkin(skinName));\n            skeletonGraphic.Skeleton.SetSkin(skin);\n            skeletonGraphic.Skeleton.SetSlotsToSetupPose();\n            skeletonGraphic.LateUpdate();\n            skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton);\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic SetSkin(this SkeletonGraphic skeletonGraphic, List<string> skinNames)\n        {\n            var skin = new Skin(\"temp\");\n            var skeletonData = skeletonGraphic.Skeleton.Data;\n            foreach (string skinName in skinNames)\n            {\n                skin.AddSkin(skeletonData.FindSkin(skinName));\n            }\n\n            skeletonGraphic.initialSkinName = \"temp\";\n            skeletonGraphic.Skeleton.SetSkin(skin);\n            skeletonGraphic.Skeleton.SetSlotsToSetupPose();\n            skeletonGraphic.LateUpdate();\n            skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton);\n\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic ChangeAttachment(this SkeletonGraphic skeletonGraphic, string slotName,\n            string attachmentName)\n        {\n            var slotIndex = skeletonGraphic.Skeleton.Data.FindSlot(slotName).Index;\n            var attachment = skeletonGraphic.Skeleton.GetAttachment(slotIndex, attachmentName);\n            var skin = new Skin(\"temp\");\n            skin.SetAttachment(slotIndex, slotName, attachment);\n            skeletonGraphic.Skeleton.SetSkin(skin);\n            skeletonGraphic.Skeleton.SetSlotsToSetupPose();\n            skeletonGraphic.LateUpdate();\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic ChangeAttachment(this SkeletonGraphic skeletonGraphic, string slotName,\n            List<string> attachmentNames)\n        {\n            var slotIndex = skeletonGraphic.Skeleton.Data.FindSlot(slotName).Index;\n            var skin = new Skin(\"temp\");\n            foreach (var attachmentName in attachmentNames)\n            {\n                var attachment = skeletonGraphic.Skeleton.GetAttachment(slotIndex, attachmentName);\n                skin.SetAttachment(slotIndex, slotName, attachment);\n            }\n\n            skeletonGraphic.Skeleton.SetSkin(skin);\n            skeletonGraphic.Skeleton.SetSlotsToSetupPose();\n            skeletonGraphic.LateUpdate();\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic MixSkin(this SkeletonGraphic skeletonGraphic, string mixSkinName)\n        {\n            Skin skin = new Skin(\"temp\");\n            skin.AddSkin(skeletonGraphic.Skeleton.Data.FindSkin(mixSkinName));\n            skeletonGraphic.Skeleton.SetSkin(skin);\n            skeletonGraphic.Skeleton.SetSlotsToSetupPose();\n            skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton);\n            return skeletonGraphic;\n        }\n\n        public static SkeletonGraphic MixSkin(this SkeletonGraphic skeletonGraphic, List<string> mixSkinNames)\n        {\n            Skin skin = new Skin(\"temp\");\n            foreach (var mixSkinName in mixSkinNames)\n            {\n                skin.AddSkin(skeletonGraphic.Skeleton.Data.FindSkin(mixSkinName));\n            }\n\n            skeletonGraphic.Skeleton.SetSkin(skin);\n            skeletonGraphic.Skeleton.SetSlotsToSetupPose();\n            skeletonGraphic.AnimationState.Apply(skeletonGraphic.Skeleton);\n            return skeletonGraphic;\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "VirtueSky/Misc/Common.SkeletonGraphic.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1c6229e62edb46d5abee83d47f591741\ntimeCreated: 1708067235"
  },
  {
    "path": "VirtueSky/Misc/Common.Tag.cs",
    "content": "﻿using System.Linq;\nusing UnityEngine;\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        public static T FindComponentInChildWithTag<T>(this GameObject parent, string tag) where T : Component\n        {\n            Transform t = parent.transform;\n            foreach (Transform tr in t)\n            {\n                if (tr.tag == tag)\n                {\n                    return tr.GetComponent<T>();\n                }\n            }\n\n            return null;\n        }\n\n        public static GameObject SetLayerForAllChildObject(this GameObject obj, int layerIndex)\n        {\n            obj.layer = layerIndex;\n            obj.GetComponentsInChildren<Transform>().ToList().ForEach(x => { x.gameObject.layer = layerIndex; });\n            return obj;\n        }\n\n        public static GameObject SetLayer(this GameObject obj, int layerIndex)\n        {\n            obj.layer = layerIndex;\n            return obj;\n        }\n\n        public static GameObject SetTagForAllChildObject(this GameObject obj, string tag)\n        {\n            obj.tag = tag;\n            obj.GetComponentsInChildren<Transform>().ToList().ForEach(x => { x.gameObject.tag = tag; });\n            return obj;\n        }\n\n        public static GameObject SetTag(this GameObject obj, string tag)\n        {\n            obj.gameObject.tag = tag;\n            return obj;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Tag.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7a60703267c2469f8401ae2860c92fd9\ntimeCreated: 1699240721"
  },
  {
    "path": "VirtueSky/Misc/Common.Text.cs",
    "content": "using System.Runtime.CompilerServices;\nusing UnityEngine;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Misc\n{\n    public partial class Common\n    {\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"text\"></param>\n        /// <param name=\"color\">html color, not include #</param>\n        /// <returns></returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string SetColor(this string text, string color)\n        {\n            return $\"<color=#{color}>{text}</color>\";\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string SetColor(this string text, UnityEngine.Color color)\n        {\n            return $\"<color={color.ToHtmlStringRGBA()}>{text}</color>\";\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string SetColor(this string text, CustomColor customColor)\n        {\n            Color color = customColor.ToColor();\n            return $\"<color={color.ToHtmlStringRGBA()}>{text}</color>\";\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string SetSize(this string text, int size)\n        {\n            return $\"<size={size}>{text}</size>\";\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string ToBold(this string text)\n        {\n            return $\"<b>{text}</b>\";\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string ToItalic(this string text)\n        {\n            return $\"<i>{text}</i>\";\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static string ToWhiteBold(this string text)\n        {\n            return text.ToBold().SetColor(UnityEngine.Color.white);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Text.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 86de5ed581ce4424a9f394e8a6fe63ec\ntimeCreated: 1729224673"
  },
  {
    "path": "VirtueSky/Misc/Common.Transform.cs",
    "content": "﻿using System;\nusing PrimeTween;\nusing UnityEngine;\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        public static Transform ClearTransform(this Transform transform)\n        {\n            var childs = transform.childCount;\n            for (int i = childs - 1; i >= 0; i--)\n            {\n                UnityEngine.Object.DestroyImmediate(transform.GetChild(i).gameObject, true);\n            }\n\n            return transform;\n        }\n\n        public static void Shrug(this Transform transformObj, float time, float strength = .1f,\n            Ease easingTypes = Ease.OutQuad,\n            Action completed = null)\n        {\n            Tween tween = default;\n            Vector3 baseScale = transformObj.localScale;\n            Vector3 targetBounceX = new Vector3(1 + strength, 1 - strength) * baseScale.x;\n            Vector3 targetBounceY = new Vector3(1 - strength, 1 + strength) * baseScale.y;\n            tween = Tween.Scale(transformObj, targetBounceX, time / 3, easingTypes).OnComplete(() =>\n            {\n                Tween.Scale(transformObj, targetBounceY, time / 3, easingTypes).OnComplete(() =>\n                {\n                    Tween.Scale(transformObj, baseScale, time / 3, easingTypes).OnComplete(() =>\n                    {\n                        tween.Stop();\n                        completed?.Invoke();\n                    });\n                });\n            });\n        }\n\n        public static Camera CameraShake(this Camera camera, float strengthFactor = 1.0f, float duration = 0.5f,\n            int frequency = 10)\n        {\n            Tween.ShakeCamera(camera, strengthFactor, duration, frequency);\n            return camera;\n        }\n\n        /// <summary>\n        /// Convert UI positon to world position\n        /// </summary>\n        /// <param name=\"transform\">transform is transform in canvas space (RectTransfom</param>\n        /// <param name=\"camera\"></param>\n        /// <returns></returns>\n        public static Vector2 ToWorldPosition(this RectTransform transform, Camera camera = null)\n        {\n            var cam = camera;\n            if (cam == null) cam = Camera.main;\n            if (cam == null) return Vector2.zero;\n            var pos = cam.ViewportToWorldPoint(transform.position);\n            var worldPosition = cam.WorldToViewportPoint(pos);\n            return worldPosition;\n        }\n\n\n        #region Position X Y Z\n\n        public static void SetPosition(this Transform transform, in Vector3 v3)\n        {\n            transform.position = v3;\n        }\n\n        public static void SetPositionX(this Transform transform, float x)\n        {\n            var v3 = transform.position;\n            v3.x = x;\n            transform.position = v3;\n        }\n\n\n        public static void SetPositionY(this Transform transform, float y)\n        {\n            var v3 = transform.position;\n            v3.y = y;\n            transform.position = v3;\n        }\n\n\n        public static void SetPositionZ(this Transform transform, float z)\n        {\n            var v3 = transform.position;\n            v3.z = z;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Position XY\n\n        public static void SetPositionXY(this Transform transform, in Vector2 v2)\n        {\n            transform.position = new Vector3(v2.x, v2.y, transform.position.z);\n        }\n\n\n        public static void SetPositionXY(this Transform transform, float x, float y)\n        {\n            transform.position = new Vector3(x, y, transform.position.z);\n        }\n\n\n        public static void SetPositionXY(this Transform transform, Transform target)\n        {\n            var v3 = target.position;\n            v3.z = transform.position.z;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Position XZ\n\n        public static void GetPositionXZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.position;\n            v2.x = v3.x;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetPositionXZ(this Transform transform)\n        {\n            var v3 = transform.position;\n            return new Vector2(v3.x, v3.z);\n        }\n\n\n        public static void SetPositionXZ(this Transform transform, in Vector2 v2)\n        {\n            transform.position = new Vector3(v2.x, transform.position.y, v2.y);\n        }\n\n\n        public static void SetPositionXZ(this Transform transform, float x, float z)\n        {\n            transform.position = new Vector3(x, transform.position.y, z);\n        }\n\n\n        public static void SetPositionXZ(this Transform transform, Transform target)\n        {\n            var v3 = target.position;\n            v3.y = transform.position.y;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Position YZ\n\n        public static void GetPositionYZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.position;\n            v2.x = v3.y;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetPositionYZ(this Transform transform)\n        {\n            var v3 = transform.position;\n            return new Vector2(v3.y, v3.z);\n        }\n\n\n        public static void SetPositionYZ(this Transform transform, in Vector2 v2)\n        {\n            transform.position = new Vector3(transform.position.x, v2.x, v2.y);\n        }\n\n\n        public static void SetPositionYZ(this Transform transform, float y, float z)\n        {\n            transform.position = new Vector3(transform.position.x, y, z);\n        }\n\n\n        public static void SetPositionYZ(this Transform transform, Transform target)\n        {\n            var v3 = target.position;\n            v3.x = transform.position.x;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Position X Y Z\n\n        public static void SetRelativePosition(this Transform transform, in Vector3 v3)\n        {\n            transform.position += v3;\n        }\n\n        public static void SetRelativePositionX(this Transform transform, float x)\n        {\n            var v3 = transform.position;\n            v3.x += x;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionY(this Transform transform, float y)\n        {\n            var v3 = transform.position;\n            v3.y += y;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionZ(this Transform transform, float z)\n        {\n            var v3 = transform.position;\n            v3.z += z;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Position XY\n\n        public static void SetRelativePositionXY(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.position;\n            v3.x += v2.x;\n            v3.y += v2.y;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionXY(this Transform transform, float x, float y)\n        {\n            var v3 = transform.position;\n            v3.x += x;\n            v3.y += y;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionXY(this Transform transform, Transform target)\n        {\n            var v3 = transform.position;\n            var targetV3 = target.position;\n            v3.x += targetV3.x;\n            v3.y += targetV3.y;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Position XZ\n\n        public static void SetRelativePositionXZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.position;\n            v3.x += v2.x;\n            v3.z += v2.y;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionXZ(this Transform transform, float x, float z)\n        {\n            var v3 = transform.position;\n            v3.x += x;\n            v3.z += z;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionXZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.position;\n            var targetV3 = target.position;\n            v3.x += targetV3.x;\n            v3.z += targetV3.z;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Position YZ\n\n        public static void SetRelativePositionYZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.position;\n            v3.y += v2.x;\n            v3.z += v2.y;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionYZ(this Transform transform, float y, float z)\n        {\n            var v3 = transform.position;\n            v3.y += y;\n            v3.z += z;\n            transform.position = v3;\n        }\n\n\n        public static void SetRelativePositionYZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.position;\n            var targetV3 = target.position;\n            v3.y += targetV3.y;\n            v3.z += targetV3.z;\n            transform.position = v3;\n        }\n\n        #endregion\n\n\n        #region Local Position X Y Z\n\n        public static void SetLocalPositionX(this Transform transform, float x)\n        {\n            var v3 = transform.localPosition;\n            v3.x = x;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetLocalPositionY(this Transform transform, float y)\n        {\n            var v3 = transform.localPosition;\n            v3.y = y;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetLocalPositionZ(this Transform transform, float z)\n        {\n            var v3 = transform.localPosition;\n            v3.z = z;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Local Position XY\n\n        public static void SetLocalPositionXY(this Transform transform, in Vector2 v2)\n        {\n            transform.localPosition = new Vector3(v2.x, v2.y, transform.localPosition.z);\n        }\n\n\n        public static void SetLocalPositionXY(this Transform transform, float x, float y)\n        {\n            transform.localPosition = new Vector3(x, y, transform.localPosition.z);\n        }\n\n\n        public static void SetLocalPositionXY(this Transform transform, Transform target)\n        {\n            var v3 = target.localPosition;\n            v3.z = transform.localPosition.z;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Local Position XZ\n\n        public static void GetLocalPositionXZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.localPosition;\n            v2.x = v3.x;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetLocalPositionXZ(this Transform transform)\n        {\n            var v3 = transform.localPosition;\n            return new Vector2(v3.x, v3.z);\n        }\n\n\n        public static void SetLocalPositionXZ(this Transform transform, in Vector2 v2)\n        {\n            transform.localPosition = new Vector3(v2.x, transform.localPosition.y, v2.y);\n        }\n\n\n        public static void SetLocalPositionXZ(this Transform transform, float x, float z)\n        {\n            transform.localPosition = new Vector3(x, transform.localPosition.y, z);\n        }\n\n\n        public static void SetLocalPositionXZ(this Transform transform, Transform target)\n        {\n            var v3 = target.localPosition;\n            v3.y = transform.localPosition.y;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Local Position YZ\n\n        public static void GetLocalPositionYZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.localPosition;\n            v2.x = v3.y;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetLocalPositionYZ(this Transform transform)\n        {\n            var v3 = transform.localPosition;\n            return new Vector2(v3.y, v3.z);\n        }\n\n\n        public static void SetLocalPositionYZ(this Transform transform, in Vector2 v2)\n        {\n            transform.localPosition = new Vector3(transform.localPosition.x, v2.x, v2.y);\n        }\n\n\n        public static void SetLocalPositionYZ(this Transform transform, float y, float z)\n        {\n            transform.localPosition = new Vector3(transform.localPosition.x, y, z);\n        }\n\n\n        public static void SetLocalPositionYZ(this Transform transform, Transform target)\n        {\n            var v3 = target.localPosition;\n            v3.x = transform.localPosition.x;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Position X Y Z\n\n        public static void SetRelativeLocalPositionX(this Transform transform, float x)\n        {\n            var v3 = transform.localPosition;\n            v3.x += x;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionY(this Transform transform, float y)\n        {\n            var v3 = transform.localPosition;\n            v3.y += y;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionZ(this Transform transform, float z)\n        {\n            var v3 = transform.localPosition;\n            v3.z += z;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Position XY\n\n        public static void SetRelativeLocalPositionXY(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localPosition;\n            v3.x += v2.x;\n            v3.y += v2.y;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionXY(this Transform transform, float x, float y)\n        {\n            var v3 = transform.localPosition;\n            v3.x += x;\n            v3.y += y;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionXY(this Transform transform, Transform target)\n        {\n            var v3 = transform.localPosition;\n            var targetV3 = target.localPosition;\n            v3.x += targetV3.x;\n            v3.y += targetV3.y;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Position XZ\n\n        public static void SetRelativeLocalPositionXZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localPosition;\n            v3.x += v2.x;\n            v3.z += v2.y;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionXZ(this Transform transform, float x, float z)\n        {\n            var v3 = transform.localPosition;\n            v3.x += x;\n            v3.z += z;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionXZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.localPosition;\n            var targetV3 = target.localPosition;\n            v3.x += targetV3.x;\n            v3.z += targetV3.z;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Postion YZ\n\n        public static void SetRelativeLocalPositionYZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localPosition;\n            v3.y += v2.x;\n            v3.z += v2.y;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionYZ(this Transform transform, float y, float z)\n        {\n            var v3 = transform.localPosition;\n            v3.y += y;\n            v3.z += z;\n            transform.localPosition = v3;\n        }\n\n\n        public static void SetRelativeLocalPositionYZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.localPosition;\n            var targetV3 = target.localPosition;\n            v3.y += targetV3.y;\n            v3.z += targetV3.z;\n            transform.localPosition = v3;\n        }\n\n        #endregion\n\n\n        #region Scale X Y Z\n\n        public static void SetScaleX(this Transform transform, float x)\n        {\n            var v3 = transform.localScale;\n            v3.x = x;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetScaleY(this Transform transform, float y)\n        {\n            var v3 = transform.localScale;\n            v3.y = y;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetScaleZ(this Transform transform, float z)\n        {\n            var v3 = transform.localScale;\n            v3.z = z;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Scale XY\n\n        public static void SetScaleXY(this Transform transform, in Vector2 v2)\n        {\n            transform.localScale = new Vector3(v2.x, v2.y, transform.localScale.z);\n        }\n\n\n        public static void SetScaleXY(this Transform transform, float x, float y)\n        {\n            transform.localScale = new Vector3(x, y, transform.localScale.z);\n        }\n\n\n        public static void SetScaleXY(this Transform transform, float value)\n        {\n            transform.localScale = new Vector3(value, value, transform.localScale.z);\n        }\n\n\n        public static void SetScaleXY(this Transform transform, Transform target)\n        {\n            var v3 = target.localScale;\n            v3.z = transform.localScale.z;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Scale XZ\n\n        public static void GetScaleXZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.localScale;\n            v2.x = v3.x;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetScaleXZ(this Transform transform)\n        {\n            var v3 = transform.localScale;\n            return new Vector2(v3.x, v3.z);\n        }\n\n\n        public static void SetScaleXZ(this Transform transform, in Vector2 v2)\n        {\n            transform.localScale = new Vector3(v2.x, transform.localScale.y, v2.y);\n        }\n\n\n        public static void SetScaleXZ(this Transform transform, float x, float z)\n        {\n            transform.localScale = new Vector3(x, transform.localScale.y, z);\n        }\n\n\n        public static void SetScaleXZ(this Transform transform, float value)\n        {\n            transform.localScale = new Vector3(value, transform.localScale.y, value);\n        }\n\n\n        public static void SetScaleXZ(this Transform transform, Transform target)\n        {\n            var v3 = target.localScale;\n            v3.y = transform.localScale.y;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Scale YZ\n\n        public static void GetScaleYZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.localScale;\n            v2.x = v3.y;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetScaleYZ(this Transform transform)\n        {\n            var v3 = transform.localScale;\n            return new Vector2(v3.y, v3.z);\n        }\n\n\n        public static void SetScaleYZ(this Transform transform, in Vector2 v2)\n        {\n            transform.localScale = new Vector3(transform.localScale.x, v2.x, v2.y);\n        }\n\n\n        public static void SetScaleYZ(this Transform transform, float y, float z)\n        {\n            transform.localScale = new Vector3(transform.localScale.x, y, z);\n        }\n\n\n        public static void SetScaleYZ(this Transform transform, float value)\n        {\n            transform.localScale = new Vector3(transform.localScale.x, value, value);\n        }\n\n\n        public static void SetScaleYZ(this Transform transform, Transform target)\n        {\n            var v3 = target.localScale;\n            v3.x = transform.localScale.x;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Scale\n\n        public static void SetScale(this Transform transform, float value)\n        {\n            transform.localScale = new Vector3(value, value, value);\n        }\n\n        #endregion\n\n\n        #region Relative Scale X Y Z\n\n        public static void SetRelativeScaleX(this Transform transform, float x)\n        {\n            var v3 = transform.localScale;\n            v3.x += x;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleY(this Transform transform, float y)\n        {\n            var v3 = transform.localScale;\n            v3.y += y;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleZ(this Transform transform, float z)\n        {\n            var v3 = transform.localScale;\n            v3.z += z;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Scale XY\n\n        public static void SetRelativeScaleXY(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localScale;\n            v3.x += v2.x;\n            v3.y += v2.y;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleXY(this Transform transform, float x, float y)\n        {\n            var v3 = transform.localScale;\n            v3.x += x;\n            v3.y += y;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleXY(this Transform transform, float value)\n        {\n            var v3 = transform.localScale;\n            v3.x += value;\n            v3.y += value;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleXY(this Transform transform, Transform target)\n        {\n            var v3 = transform.localScale;\n            var targetV3 = target.localScale;\n            v3.x += targetV3.x;\n            v3.y += targetV3.y;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Scale XZ\n\n        public static void SetRelativeScaleXZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localScale;\n            v3.x += v2.x;\n            v3.z += v2.y;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleXZ(this Transform transform, float x, float z)\n        {\n            var v3 = transform.localScale;\n            v3.x += x;\n            v3.z += z;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleXZ(this Transform transform, float value)\n        {\n            var v3 = transform.localScale;\n            v3.x += value;\n            v3.z += value;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleXZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.localScale;\n            var targetV3 = target.localScale;\n            v3.x += targetV3.x;\n            v3.z += targetV3.z;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Scale YZ\n\n        public static void SetRelativeScaleYZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localScale;\n            v3.y += v2.x;\n            v3.z += v2.y;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleYZ(this Transform transform, float y, float z)\n        {\n            var v3 = transform.localScale;\n            v3.y += y;\n            v3.z += z;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleYZ(this Transform transform, float value)\n        {\n            var v3 = transform.localScale;\n            v3.y += value;\n            v3.z += value;\n            transform.localScale = v3;\n        }\n\n\n        public static void SetRelativeScaleYZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.localScale;\n            var targetV3 = target.localScale;\n            v3.y += targetV3.y;\n            v3.z += targetV3.z;\n            transform.localScale = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Scale\n\n        public static void SetRelativeScale(this Transform transform, float value)\n        {\n            transform.localScale += new Vector3(value, value, value);\n        }\n\n        #endregion\n\n\n        #region Rotation X Y Z\n\n        public static void SetRotationX(this Transform transform, float x)\n        {\n            var v3 = transform.eulerAngles;\n            v3.x = x;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRotationY(this Transform transform, float y)\n        {\n            var v3 = transform.eulerAngles;\n            v3.y = y;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRotationZ(this Transform transform, float z)\n        {\n            var v3 = transform.eulerAngles;\n            v3.z = z;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Rotation XY\n\n        public static void SetRotationXY(this Transform transform, in Vector2 v2)\n        {\n            transform.eulerAngles = new Vector3(v2.x, v2.y, transform.eulerAngles.z);\n        }\n\n\n        public static void SetRotationXY(this Transform transform, float x, float y)\n        {\n            transform.eulerAngles = new Vector3(x, y, transform.eulerAngles.z);\n        }\n\n\n        public static void SetRotationXY(this Transform transform, Transform target)\n        {\n            var v3 = target.eulerAngles;\n            v3.z = transform.eulerAngles.z;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Rotation XZ\n\n        public static void GetRotationXZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.eulerAngles;\n            v2.x = v3.x;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetRotationXZ(this Transform transform)\n        {\n            var v3 = transform.eulerAngles;\n            return new Vector2(v3.x, v3.z);\n        }\n\n\n        public static void SetRotationXZ(this Transform transform, in Vector2 v2)\n        {\n            transform.eulerAngles = new Vector3(v2.x, transform.eulerAngles.y, v2.y);\n        }\n\n\n        public static void SetRotationXZ(this Transform transform, float x, float z)\n        {\n            transform.eulerAngles = new Vector3(x, transform.eulerAngles.y, z);\n        }\n\n\n        public static void SetRotationXZ(this Transform transform, Transform target)\n        {\n            var v3 = target.eulerAngles;\n            v3.y = transform.eulerAngles.y;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Rotation YZ\n\n        public static void GetRotationYZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.eulerAngles;\n            v2.x = v3.y;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetRotationYZ(this Transform transform)\n        {\n            var v3 = transform.eulerAngles;\n            return new Vector2(v3.y, v3.z);\n        }\n\n\n        public static void SetRotationYZ(this Transform transform, in Vector2 v2)\n        {\n            transform.eulerAngles = new Vector3(transform.eulerAngles.x, v2.x, v2.y);\n        }\n\n\n        public static void SetRotationYZ(this Transform transform, float y, float z)\n        {\n            transform.eulerAngles = new Vector3(transform.eulerAngles.x, y, z);\n        }\n\n\n        public static void SetRotationYZ(this Transform transform, Transform target)\n        {\n            var v3 = target.eulerAngles;\n            v3.x = transform.eulerAngles.x;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Rotation X Y Z\n\n        public static void SetRelativeRotationX(this Transform transform, float x)\n        {\n            var v3 = transform.eulerAngles;\n            v3.x += x;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationY(this Transform transform, float y)\n        {\n            var v3 = transform.eulerAngles;\n            v3.y += y;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationZ(this Transform transform, float z)\n        {\n            var v3 = transform.eulerAngles;\n            v3.z += z;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Rotation XY\n\n        public static void SetRelativeRotationXY(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.eulerAngles;\n            v3.x += v2.x;\n            v3.y += v2.y;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationXY(this Transform transform, float x, float y)\n        {\n            var v3 = transform.eulerAngles;\n            v3.x += x;\n            v3.y += y;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationXY(this Transform transform, Transform target)\n        {\n            var v3 = transform.eulerAngles;\n            var targetV3 = target.eulerAngles;\n            v3.x += targetV3.x;\n            v3.y += targetV3.y;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Rotation XZ\n\n        public static void SetRelativeRotationXZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.eulerAngles;\n            v3.x += v2.x;\n            v3.z += v2.y;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationXZ(this Transform transform, float x, float z)\n        {\n            var v3 = transform.eulerAngles;\n            v3.x += x;\n            v3.z += z;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationXZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.eulerAngles;\n            var targetV3 = target.eulerAngles;\n            v3.x += targetV3.x;\n            v3.z += targetV3.z;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Rotation YZ\n\n        public static void SetRelativeRotationYZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.eulerAngles;\n            v3.y += v2.x;\n            v3.z += v2.y;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationYZ(this Transform transform, float y, float z)\n        {\n            var v3 = transform.eulerAngles;\n            v3.y += y;\n            v3.z += z;\n            transform.eulerAngles = v3;\n        }\n\n\n        public static void SetRelativeRotationYZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.eulerAngles;\n            var targetV3 = target.eulerAngles;\n            v3.y += targetV3.y;\n            v3.z += targetV3.z;\n            transform.eulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Local Rotation X Y Z\n\n        public static void SetLocalRotationX(this Transform transform, float x)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.x = x;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetLocalRotationY(this Transform transform, float y)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.y = y;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetLocalRotationZ(this Transform transform, float z)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.z = z;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Local Rotation XY\n\n        public static void SetLocalRotationXY(this Transform transform, in Vector2 v2)\n        {\n            transform.localEulerAngles = new Vector3(v2.x, v2.y, transform.localEulerAngles.z);\n        }\n\n\n        public static void SetLocalRotationXY(this Transform transform, float x, float y)\n        {\n            transform.localEulerAngles = new Vector3(x, y, transform.localEulerAngles.z);\n        }\n\n\n        public static void SetLocalRotationXY(this Transform transform, Transform target)\n        {\n            var v3 = target.localEulerAngles;\n            v3.z = transform.localEulerAngles.z;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Local Rotation XZ\n\n        public static void GetLocalRotationXZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.localEulerAngles;\n            v2.x = v3.x;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetLocalRotationXZ(this Transform transform)\n        {\n            var v3 = transform.localEulerAngles;\n            return new Vector2(v3.x, v3.z);\n        }\n\n\n        public static void SetLocalRotationXZ(this Transform transform, in Vector2 v2)\n        {\n            transform.localEulerAngles = new Vector3(v2.x, transform.localEulerAngles.y, v2.y);\n        }\n\n\n        public static void SetLocalRotationXZ(this Transform transform, float x, float z)\n        {\n            transform.localEulerAngles = new Vector3(x, transform.localEulerAngles.y, z);\n        }\n\n\n        public static void SetLocalRotationXZ(this Transform transform, Transform target)\n        {\n            var v3 = target.localEulerAngles;\n            v3.y = transform.localEulerAngles.y;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Local Rotation YZ\n\n        public static void GetLocalRotationYZ(this Transform transform, out Vector2 v2)\n        {\n            var v3 = transform.localEulerAngles;\n            v2.x = v3.y;\n            v2.y = v3.z;\n        }\n\n\n        public static Vector2 GetLocalRotationYZ(this Transform transform)\n        {\n            var v3 = transform.localEulerAngles;\n            return new Vector2(v3.y, v3.z);\n        }\n\n\n        public static void SetLocalRotationYZ(this Transform transform, in Vector2 v2)\n        {\n            transform.localEulerAngles = new Vector3(transform.localEulerAngles.x, v2.x, v2.y);\n        }\n\n\n        public static void SetLocalRotationYZ(this Transform transform, float y, float z)\n        {\n            transform.localEulerAngles = new Vector3(transform.localEulerAngles.x, y, z);\n        }\n\n\n        public static void SetLocalRotationYZ(this Transform transform, Transform target)\n        {\n            var v3 = target.localEulerAngles;\n            v3.x = transform.localEulerAngles.x;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Rotation X Y Z\n\n        public static void SetRelativeLocalRotationX(this Transform transform, float x)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.x += x;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationY(this Transform transform, float y)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.y += y;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationZ(this Transform transform, float z)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.z += z;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Rotation XY\n\n        public static void SetRelativeLocalRotationXY(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.x += v2.x;\n            v3.y += v2.y;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationXY(this Transform transform, float x, float y)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.x += x;\n            v3.y += y;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationXY(this Transform transform, Transform target)\n        {\n            var v3 = transform.localEulerAngles;\n            var targetV3 = target.localEulerAngles;\n            v3.x += targetV3.x;\n            v3.y += targetV3.y;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Rotation XZ\n\n        public static void SetRelativeLocalRotationXZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.x += v2.x;\n            v3.z += v2.y;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationXZ(this Transform transform, float x, float z)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.x += x;\n            v3.z += z;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationXZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.localEulerAngles;\n            var targetV3 = target.localEulerAngles;\n            v3.x += targetV3.x;\n            v3.z += targetV3.z;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Local Rotation YZ\n\n        public static void SetRelativeLocalRotationYZ(this Transform transform, in Vector2 v2)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.y += v2.x;\n            v3.z += v2.y;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationYZ(this Transform transform, float y, float z)\n        {\n            var v3 = transform.localEulerAngles;\n            v3.y += y;\n            v3.z += z;\n            transform.localEulerAngles = v3;\n        }\n\n\n        public static void SetRelativeLocalRotationYZ(this Transform transform, Transform target)\n        {\n            var v3 = transform.localEulerAngles;\n            var targetV3 = target.localEulerAngles;\n            v3.y += targetV3.y;\n            v3.z += targetV3.z;\n            transform.localEulerAngles = v3;\n        }\n\n        #endregion\n\n\n        #region Anchored Position X Y Z\n\n        public static void SetAnchoredPositionX(this RectTransform rectTransform, float x)\n        {\n            var v2 = rectTransform.anchoredPosition;\n            v2.x = x;\n            rectTransform.anchoredPosition = v2;\n        }\n\n\n        public static void SetAnchoredPositionY(this RectTransform rectTransform, float y)\n        {\n            var v2 = rectTransform.anchoredPosition;\n            v2.y = y;\n            rectTransform.anchoredPosition = v2;\n        }\n\n\n        public static void SetAnchoredPositionZ(this RectTransform rectTransform, float z)\n        {\n            var v3 = rectTransform.anchoredPosition3D;\n            v3.z = z;\n            rectTransform.anchoredPosition3D = v3;\n        }\n\n        #endregion\n\n\n        #region Relative Anchored Position X Y Z\n\n        public static void SetRelativeAnchoredPositionX(this RectTransform rectTransform, float x)\n        {\n            var v2 = rectTransform.anchoredPosition;\n            v2.x += x;\n            rectTransform.anchoredPosition = v2;\n        }\n\n\n        public static void SetRelativeAnchoredPositionY(this RectTransform rectTransform, float y)\n        {\n            var v2 = rectTransform.anchoredPosition;\n            v2.y += y;\n            rectTransform.anchoredPosition = v2;\n        }\n\n\n        public static void SetRelativeAnchoredPositionZ(this RectTransform rectTransform, float z)\n        {\n            var v3 = rectTransform.anchoredPosition3D;\n            v3.z += z;\n            rectTransform.anchoredPosition3D = v3;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.Transform.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 76a24755436e4f4bb3ebb19dbf3a28b7\ntimeCreated: 1699240558"
  },
  {
    "path": "VirtueSky/Misc/Common.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing UnityEngine;\nusing UnityEngine.Networking;\nusing VirtueSky.Core;\n\nnamespace VirtueSky.Misc\n{\n    public static partial class Common\n    {\n        public static string Format(this string fmt, params object[] args) =>\n            string.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat, fmt, args);\n\n        public static bool IsInteger(this float value)\n        {\n            return (value == (int)value);\n        }\n\n        public static int GetNumberInAString(this string str)\n        {\n            try\n            {\n                var getNumb = Regex.Match(str, @\"\\d+\").Value;\n                return Int32.Parse(getNumb);\n            }\n            catch (Exception e)\n            {\n                return -1;\n            }\n\n            return -1;\n        }\n\n        public static float GetScreenRatio()\n        {\n            return (1920f / 1080f) / (Screen.height / (float)Screen.width);\n        }\n\n        public static void CallActionAndClean(ref Action action)\n        {\n            if (action == null) return;\n            var a = action;\n            a();\n            action = null;\n        }\n\n        public static void CallActionAndClean<T>(ref Action<T> action, T _value)\n        {\n            if (action == null) return;\n            var a = action;\n            a(_value);\n            action = null;\n        }\n\n\n        #region Internet Connection\n\n        private static IEnumerator internetConnectionCoroutine;\n\n        public static void StopCheckInternetConnection()\n        {\n            App.StopCoroutine(internetConnectionCoroutine);\n        }\n\n        public static void CheckInternetConnection(Action actionConnected, Action actionDisconnected)\n        {\n            if (internetConnectionCoroutine != null) App.StopCoroutine(internetConnectionCoroutine);\n            internetConnectionCoroutine = InternetConnection((isConnected) =>\n            {\n                if (isConnected)\n                {\n                    actionConnected?.Invoke();\n                }\n                else\n                {\n                    actionDisconnected?.Invoke();\n                }\n            });\n            App.StartCoroutine(internetConnectionCoroutine);\n        }\n\n        public static IEnumerator InternetConnection(Action<bool> action)\n        {\n            bool result;\n            string url = \"https://google.com\";\n#if UNITY_ANDROID\n            url = \"https://google.com\";\n#elif UNITY_IOS\n            url = \"https://captive.apple.com/hotspot-detect.html\";\n#endif\n\n            using (UnityWebRequest request = UnityWebRequest.Head(url))\n            {\n                yield return request.SendWebRequest();\n                result = !request.isNetworkError && !request.isHttpError && request.responseCode == 200 &&\n                         request.error == null;\n            }\n\n            action(result);\n            internetConnectionCoroutine = null;\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Attach a DelayHandle on to the behaviour. If the behaviour is destroyed before the DelayHandle is completed,\n        /// e.g. through a scene change, the DelayHandle callback will not execute.\n        /// </summary>\n        /// <param name=\"target\">The behaviour to attach this DelayHandle to.</param>\n        /// <param name=\"duration\">The duration to wait before the DelayHandle fires.</param>\n        /// <param name=\"onComplete\">The action to run when the DelayHandle elapses.</param>\n        /// <param name=\"onUpdate\">A function to call each tick of the DelayHandle. Takes the number of seconds elapsed since\n        /// the start of the current cycle.</param>\n        /// <param name=\"isLooped\">Whether the DelayHandle should restart after executing.</param>\n        /// <param name=\"useRealTime\">Whether the DelayHandle uses real-time(not affected by slow-mo or pausing) or\n        /// game-time(affected by time scale changes).</param>\n        public static DelayHandle Delay(\n            this MonoBehaviour target,\n            float duration,\n            Action onComplete,\n            Action<float> onUpdate = null,\n            bool isLooped = false,\n            bool useRealTime = false)\n        {\n            return App.Delay(\n                target,\n                duration,\n                onComplete,\n                onUpdate,\n                isLooped,\n                useRealTime);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Misc/Common.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ca637e462d4f747ec846934b2a8e0cc9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Misc/virtuesky.sunflower.misc.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Misc\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:ce8c6e3f188ed064f933ef35b46bf8bd\",\n        \"GUID:80ecb87cae9c44d19824e70ea7229748\",\n        \"GUID:72d1fea872bd7a449bf3818f2b0a6708\",\n        \"GUID:68765d262e2128e4ab49c983f3411946\",\n        \"GUID:4c25c05f410a3a447a75c3b0909152ef\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Misc/virtuesky.sunflower.misc.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: fca7ec166e04dc948b624a983315e2c9\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Misc.meta",
    "content": "fileFormatVersion: 2\nguid: 3231e9518727a4f5eb3ff88394428280\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Editor/NotificationWindowEditor.cs",
    "content": "using UnityEditor;\nusing VirtueSky.Notifications;\nusing VirtueSky.UtilsEditor;\n\n\npublic class NotificationWindowEditor : EditorWindow\n{\n    //  [MenuItem(\"Sunflower/Notification Channel\")]\n    public static void CreateNotificationChannel()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<NotificationVariable>(\"/Notifications\", \"notification_channel_data\");\n    }\n}"
  },
  {
    "path": "VirtueSky/Notifications/Editor/NotificationWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8680608c365dc4d7dbc7b5439e9d392d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Editor/Virtuesky.Sunflower.Notifications.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Notifications.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:3aa1a48b88c8fc84ab64d4acf89d0b4e\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Notifications/Editor/Virtuesky.Sunflower.Notifications.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 8bd745a7d8af04c528da60c6b56aa92a\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 1049fc5fd097048aaa1e56f847aa8bad\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationAndroid.cs",
    "content": "﻿#if UNITY_ANDROID && VIRTUESKY_NOTIFICATION\nusing System;\nusing System.Collections.Generic;\nusing Unity.Notifications.Android;\n\nnamespace VirtueSky.Notifications\n{\n    internal static class NotificationAndroid\n    {\n        private static readonly Dictionary<string, bool> ChannelRegistered = new Dictionary<string, bool>();\n\n        private static void RegisterNotificationChannel(string identifier, string name, string description)\n        {\n            ChannelRegistered.TryGetValue(identifier, out bool registered);\n            if (registered) return;\n\n            AndroidNotificationCenter.RegisterNotificationChannel(new AndroidNotificationChannel\n            {\n                Id = identifier, Name = name, Importance = Importance.High, Description = description\n            });\n            ChannelRegistered.Add(identifier, true);\n        }\n\n        internal static void Schedule(\n            string identifier,\n            string title,\n            string text,\n            TimeSpan timeOffset,\n            string largeIcon = null,\n            string channelName = \"Nova\",\n            string channelDescription = \"Newsletter Announcement\",\n            string smallIcon = \"icon_0\",\n            BigPictureStyle? bigPictureStyle = null,\n            bool repeat = false)\n        {\n            RegisterNotificationChannel(identifier, channelName, channelDescription);\n\n            var notification = new AndroidNotification()\n            {\n                Title = title,\n                Text = text,\n                FireTime = DateTime.Now + timeOffset,\n                Group = identifier,\n                GroupSummary = true,\n                ShouldAutoCancel = true,\n                BigPicture = bigPictureStyle,\n            };\n\n            if (repeat) notification.RepeatInterval = timeOffset;\n\n            if (largeIcon != null) notification.LargeIcon = largeIcon;\n            if (smallIcon != null) notification.SmallIcon = smallIcon;\n\n            AndroidNotificationCenter.SendNotification(notification, identifier);\n        }\n\n        internal static void ScheduleAtSpecificTime(\n            string identifier,\n            string title,\n            string text,\n            DateTime fireTime,\n            string largeIcon = null,\n            string channelName = \"Nova\",\n            string channelDescription = \"Newsletter Announcement\",\n            string smallIcon = \"icon_0\",\n            BigPictureStyle? bigPictureStyle = null,\n            bool repeat = false)\n        {\n            RegisterNotificationChannel(identifier, channelName, channelDescription);\n            var now = DateTime.Now;\n            var todayFireTime = new DateTime(now.Year, now.Month, now.Day, \n                fireTime.Hour, fireTime.Minute, fireTime.Second);\n            var adjustedFireTime = todayFireTime;\n            if (adjustedFireTime <= now)\n            {\n                adjustedFireTime = adjustedFireTime.AddDays(1);\n            }\n            \n            var timeOffset = adjustedFireTime - now;\n\n            var notification = new AndroidNotification()\n            {\n                Title = title,\n                Text = text,\n                FireTime = DateTime.Now + timeOffset,\n                Group = identifier,\n                GroupSummary = true,\n                ShouldAutoCancel = true,\n                BigPicture = bigPictureStyle,\n            };\n            \n            if (repeat)\n            {\n                notification.RepeatInterval = TimeSpan.FromDays(1);\n            }\n\n            if (largeIcon != null) notification.LargeIcon = largeIcon;\n            if (smallIcon != null) notification.SmallIcon = smallIcon;\n\n            AndroidNotificationCenter.SendNotification(notification, identifier);\n        }\n\n        internal static void CancelAllScheduled()\n        {\n            AndroidNotificationCenter.CancelAllScheduledNotifications();\n        }\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationAndroid.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 402d514dcc42447fbe9cd6f03b6a5a12\ntimeCreated: 1698142005"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationConsole.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Notifications\n{\n    internal static class NotificationConsole\n    {\n        internal static void Send(\n            string identifier,\n            string title,\n            string text,\n            string largeIcon = null,\n            string channelName = \"Nova\",\n            string channelDescription = \"Newsletter Announcement\",\n            string smallIcon = null,\n            bool bigPicture = false,\n            string namePicture = \"\")\n        {\n            Schedule(identifier,\n                title,\n                text,\n                TimeSpan.FromMilliseconds(250),\n                largeIcon,\n                channelName,\n                channelDescription,\n                smallIcon,\n                bigPicture,\n                namePicture);\n        }\n\n        internal static void Schedule(\n            string identifier,\n            string title,\n            string text,\n            TimeSpan timeOffset,\n            string largeIcon = null,\n            string channelName = \"Nova\",\n            string channelDescription = \"Newsletter Announcement\",\n            string smallIcon = null,\n            bool bigPicture = false,\n            string namePicture = \"\",\n            bool repeat = false)\n        {\n            if (string.IsNullOrEmpty(smallIcon)) smallIcon = \"icon_0\";\n            if (string.IsNullOrEmpty(largeIcon)) largeIcon = \"icon_1\";\n\n#if UNITY_ANDROID && VIRTUESKY_NOTIFICATION\n            Unity.Notifications.Android.BigPictureStyle? bigPictureStyle = null;\n            if (bigPicture)\n            {\n                bigPictureStyle = new Unity.Notifications.Android.BigPictureStyle\n                    { Picture = namePicture, ContentTitle = title, ContentDescription = text };\n            }\n\n            NotificationAndroid.Schedule(identifier,\n                title,\n                text,\n                timeOffset,\n                largeIcon,\n                channelName,\n                channelDescription,\n                smallIcon,\n                bigPictureStyle,\n                repeat);\n#elif UNITY_IOS && VIRTUESKY_NOTIFICATION\n            NotificationIOS.Schedule(identifier, title, \"\", text, timeOffset, repeat);\n#endif\n        }\n\n        internal static void ScheduleAtSpecificTime(\n            string identifier,\n            string title,\n            string text,\n            DateTime fireTime,\n            string largeIcon = null,\n            string channelName = \"Nova\",\n            string channelDescription = \"Newsletter Announcement\",\n            string smallIcon = null,\n            bool bigPicture = false,\n            string namePicture = \"\",\n            bool repeat = false)\n        {\n            if (string.IsNullOrEmpty(smallIcon)) smallIcon = \"icon_0\";\n            if (string.IsNullOrEmpty(largeIcon)) largeIcon = \"icon_1\";\n\n#if UNITY_ANDROID && VIRTUESKY_NOTIFICATION\n            Unity.Notifications.Android.BigPictureStyle? bigPictureStyle = null;\n            if (bigPicture)\n            {\n                bigPictureStyle = new Unity.Notifications.Android.BigPictureStyle\n                    { Picture = namePicture, ContentTitle = title, ContentDescription = text };\n            }\n\n            NotificationAndroid.ScheduleAtSpecificTime(identifier,\n                title,\n                text,\n                fireTime,\n                largeIcon,\n                channelName,\n                channelDescription,\n                smallIcon,\n                bigPictureStyle,\n                repeat);\n#elif UNITY_IOS && VIRTUESKY_NOTIFICATION\n            NotificationIOS.ScheduleAtSpecificTime(identifier, title, \"\", text, fireTime, repeat);\n#endif\n        }\n\n        internal static void CancelAllScheduled()\n        {\n#if UNITY_ANDROID && VIRTUESKY_NOTIFICATION\n            NotificationAndroid.CancelAllScheduled();\n#elif UNITY_IOS && VIRTUESKY_NOTIFICATION\n            NotificationIOS.CancelAllScheduled();\n#endif\n        }\n\n        internal static void ClearBadgeCounterIOS()\n        {\n#if UNITY_IOS && VIRTUESKY_NOTIFICATION\n            NotificationIOS.ClearBadgeCounter();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationConsole.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ebbfadc057d94706bce96c38e1e36dc7\ntimeCreated: 1698144094"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationIOS.cs",
    "content": "﻿#if UNITY_IOS && VIRTUESKY_NOTIFICATION\nusing System;\nusing System.Collections.Generic;\nusing Unity.Notifications.iOS;\nusing UnityEngine;\nusing Cysharp.Threading.Tasks;\n\nnamespace VirtueSky.Notifications\n{\n    internal static class NotificationIOS\n    {\n        private static Dictionary<string, bool> channelRegistered = new Dictionary<string, bool>();\n\n        internal static async UniTask RequestAuthorization()\n        {\n            var authorizationOption = AuthorizationOption.Alert | AuthorizationOption.Badge | AuthorizationOption.Sound;\n            using (var req = new AuthorizationRequest(authorizationOption, true))\n            {\n                while (!req.IsFinished)\n                {\n                    await UniTask.Yield();\n                }\n            }\n        }\n\n        private static async UniTask RegisterNotificationChannel(string identifier, string title, string subtitle,\n            string body, iOSNotificationTrigger trigger)\n        {\n            await RequestAuthorization();\n\n            if (new iOSNotificationSettings().AuthorizationStatus != AuthorizationStatus.Authorized)\n            {\n                Debug.LogError(\"IOSNotification non authorized for schedule notification\");\n            }\n\n            var unregistered = !channelRegistered.ContainsKey(identifier) || !channelRegistered[identifier];\n            if (unregistered)\n            {\n                var notification = new iOSNotification()\n                {\n                    Identifier = identifier,\n                    Title = title,\n                    Body = body,\n                    Subtitle = subtitle,\n                    ShowInForeground = true,\n                    ForegroundPresentationOption =\n                        (PresentationOption.Alert | PresentationOption.Badge | PresentationOption.Sound),\n                    CategoryIdentifier = \"category_a\",\n                    ThreadIdentifier = \"thread1\",\n                    Trigger = trigger,\n                };\n\n                try\n                {\n                    iOSNotificationCenter.ScheduleNotification(notification);\n                    channelRegistered[identifier] = true;\n                }\n                catch (Exception e)\n                {\n                    Debug.LogException(e);\n                }\n            }\n        }\n\n        internal static void Schedule(string identifier, string title, string subtitle, string text, TimeSpan fireTime,\n            bool repeat)\n        {\n            var interval = fireTime;\n            if (interval <= TimeSpan.Zero) interval = TimeSpan.FromSeconds(1);\n\n            var timeTrigger = new iOSNotificationTimeIntervalTrigger { TimeInterval = interval, Repeats = repeat };\n\n            RegisterNotificationChannel(identifier,\n                title,\n                subtitle,\n                text,\n                timeTrigger).Forget();\n        }\n\n        internal static void ScheduleAtSpecificTime(string identifier, string title, string subtitle, string text,\n            DateTime fireTime, bool repeat)\n        {\n            var now = DateTime.Now;\n\n            // Tạo thời gian fire cho hôm nay với giờ/phút/giây từ fireTime\n            var todayFireTime = new DateTime(now.Year, now.Month, now.Day,\n                fireTime.Hour, fireTime.Minute, fireTime.Second);\n\n            // Nếu thời gian hôm nay đã qua, schedule cho ngày mai\n            var adjustedFireTime = todayFireTime;\n            if (adjustedFireTime <= now)\n            {\n                adjustedFireTime = adjustedFireTime.AddDays(1);\n            }\n\n            // Tính timeOffset từ bây giờ đến thời gian fire\n            var timeOffset = adjustedFireTime - now;\n\n            var interval = timeOffset;\n            if (interval <= TimeSpan.Zero) interval = TimeSpan.FromSeconds(1);\n\n            var timeTrigger = new iOSNotificationTimeIntervalTrigger { TimeInterval = interval, Repeats = repeat };\n\n            RegisterNotificationChannel(identifier,\n                title,\n                subtitle,\n                text,\n                timeTrigger).Forget();\n        }\n\n        internal static void CancelAllScheduled()\n        {\n            iOSNotificationCenter.RemoveAllScheduledNotifications();\n        }\n\n        internal static void ClearBadgeCounter()\n        {\n            iOSNotificationCenter.ApplicationBadge = 0;\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationIOS.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d3654c229d59459fba1c774a7f4c361e\ntimeCreated: 1698142156"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationPrepare.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEngine;\nusing UnityEngine.Networking;\nusing VirtueSky.Core;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Notifications\n{\n    [EditorIcon(\"script_noti\"), HideMonoScript]\n    public class NotificationPrepare : BaseMono\n    {\n        [Space(20), SerializeField] private NotificationVariable[] notificationVariables;\n        [SerializeField] private bool autoSchedule = true;\n        \n        [Header(\"Schedule On Quit/Pause\")]\n        [SerializeField] private bool scheduleOnQuit = true;\n        [SerializeField] private NotificationVariable[] notificationOnQuitVariables;\n        \n        private void Start()\n        {\n#if UNITY_ANDROID\n            PermissionPostNotification();\n            if (Application.isMobilePlatform)\n            {\n                var strs = new List<string>();\n\n                foreach (var variable in notificationVariables)\n                {\n                    if (!variable.bigPicture) continue;\n                    if (!strs.Contains(variable.namePicture)) strs.Add(variable.namePicture);\n                }\n                \n                foreach (var variable in notificationOnQuitVariables)\n                {\n                    if (variable == null || !variable.bigPicture) continue;\n                    if (!strs.Contains(variable.namePicture)) strs.Add(variable.namePicture);\n                }\n\n                foreach (string s in strs)\n                {\n                    App.StartCoroutine(PrepareImage(Application.persistentDataPath, s));\n                }\n            }\n#endif\n            CancelAllScheduledNotifications();\n            \n        }\n        \n        private void OnApplicationPause(bool pauseStatus)\n        {\n            if (pauseStatus)\n            {\n                ScheduleOnQuit();\n                if (autoSchedule) AutoSchedule();\n            }\n            else\n            {\n                CancelAllScheduledNotifications();\n            }\n        }\n        \n        private void ScheduleOnQuit()\n        {\n            if (!scheduleOnQuit) return;\n            if (!Application.isMobilePlatform) return;\n            \n            foreach (var notification in notificationOnQuitVariables)\n            {\n                if (notification != null)\n                {\n                    notification.Schedule();\n                }\n            }\n        }\n        \n        private void CancelAllScheduledNotifications()\n        {\n            if (!Application.isMobilePlatform) return;\n            NotificationConsole.CancelAllScheduled();\n        }\n        \n#if UNITY_ANDROID\n        private IEnumerator PrepareImage(string destDir, string filename)\n        {\n            string path = Path.Combine(destDir, filename);\n            if (File.Exists(path)) yield break;\n            using var uwr =\n                UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, filename));\n            yield return uwr.SendWebRequest();\n            File.WriteAllBytes(path, uwr.downloadHandler.data);\n        }\n\n        void PermissionPostNotification()\n        {\n            if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(\"android.permission.POST_NOTIFICATIONS\"))\n            {\n                UnityEngine.Android.Permission.RequestUserPermission(\"android.permission.POST_NOTIFICATIONS\");\n            }\n        }\n\n#endif\n        void AutoSchedule()\n        {\n            foreach (var notification in notificationVariables)\n            {\n                notification.Schedule();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationPrepare.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c4cadfcc9c3540478d6f4e3511ffac6e\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 7e5f4750d7e998c40a41333bba35d8b8, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationVariable.cs",
    "content": "﻿using System;\nusing System.IO;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.Notifications\n{\n    [CreateAssetMenu(fileName = \"notification_channel_data.asset\",\n        menuName = \"Sunflower/Notification Channel\")]\n    [EditorIcon(\"scriptable_notification\")]\n    public class NotificationVariable : ScriptableObject\n    {\n        [Serializable]\n        public class NotificationData\n        {\n            public string title;\n            public string message;\n\n            public NotificationData(string title, string message)\n            {\n                this.title = title;\n                this.message = message;\n            }\n        }\n\n        public enum ScheduleMode\n        {\n            RelativeTime,    // Schedule sau X phút từ thời điểm hiện tại\n            SpecificTime     // Schedule vào giờ cụ thể (ví dụ: 6h tối ngày mai)\n        }\n\n        [SerializeField] private string identifier;\n        [SerializeField] private ScheduleMode scheduleMode = ScheduleMode.RelativeTime;\n        \n        // === Relative Time Settings ===\n        [ShowIf(nameof(scheduleMode), ScheduleMode.RelativeTime)]\n        [SerializeField] private bool isRemoteConfigTimeSchedule;\n\n        [ShowIf(nameof(isRemoteConfigTimeSchedule)), SerializeField]\n        private IntegerVariable remoteConfigMinute;\n\n        [HideIf(nameof(isRemoteConfigTimeSchedule))]\n        [ShowIf(nameof(scheduleMode), ScheduleMode.RelativeTime)]\n        public int minute;\n\n        // === Specific Time Settings ===\n        [ShowIf(nameof(scheduleMode), ScheduleMode.SpecificTime)]\n        [SerializeField, Range(0, 23)] private int targetHour = 18; // 6h tối\n        \n        [ShowIf(nameof(scheduleMode), ScheduleMode.SpecificTime)]\n        [SerializeField, Range(0, 59)] private int targetMinute = 0;\n\n        [SerializeField] private bool repeat;\n        [SerializeField] internal bool bigPicture;\n\n        [ShowIf(nameof(bigPicture))]\n#if UNITY_EDITOR\n        [HelpBox(\n            \"File big picture must be place in folder StreamingAsset, Name Picture must contains file extension ex .jpg\")]\n#endif\n\n        [SerializeField]\n        internal string namePicture;\n\n        [SerializeField] internal bool overrideIcon;\n\n        [SerializeField, ShowIf(nameof(overrideIcon))]\n        internal string smallIcon = \"icon_0\";\n\n        [SerializeField, ShowIf(nameof(overrideIcon))]\n        internal string largeIcon = \"icon_1\";\n\n\n        [SerializeField] private NotificationData[] datas;\n\n        int GetMinute()\n        {\n            if (isRemoteConfigTimeSchedule)\n            {\n                return remoteConfigMinute.Value;\n            }\n\n            return minute;\n        }\n\n        DateTime? GetFireTime()\n        {\n            if (scheduleMode == ScheduleMode.SpecificTime)\n            {\n                var now = DateTime.Now;\n                return new DateTime(now.Year, now.Month, now.Day, \n                    targetHour, targetMinute, 0);\n            }\n            \n            return null; // RelativeTime mode không cần DateTime cụ thể\n        }\n\n        public void Send()\n        {\n            if (!Application.isMobilePlatform) return;\n            var data = datas.PickRandom();\n            string pathPicture = Path.Combine(Application.persistentDataPath, namePicture);\n            NotificationConsole.Send(identifier,\n                data.title,\n                data.message,\n                smallIcon: smallIcon,\n                largeIcon: largeIcon,\n                bigPicture: bigPicture,\n                namePicture: pathPicture);\n        }\n\n        public void Schedule()\n        {\n            if (!Application.isMobilePlatform) return;\n            var data = datas.PickRandom();\n\n            string pathPicture = Path.Combine(Application.persistentDataPath, namePicture);\n\n            if (scheduleMode == ScheduleMode.SpecificTime)\n            {\n                // Schedule vào giờ cụ thể\n                var fireTime = GetFireTime();\n                if (fireTime.HasValue)\n                {\n                    NotificationConsole.ScheduleAtSpecificTime(identifier,\n                        data.title,\n                        data.message,\n                        fireTime.Value,\n                        smallIcon: smallIcon,\n                        largeIcon: largeIcon,\n                        bigPicture: bigPicture,\n                        namePicture: pathPicture,\n                        repeat: repeat); // Repeat interval cố định 24h\n                }\n            }\n            else\n            {\n                // Schedule theo khoảng thời gian tương đối (logic cũ)\n                NotificationConsole.Schedule(identifier,\n                    data.title,\n                    data.message,\n                    TimeSpan.FromMinutes(GetMinute()),\n                    smallIcon: smallIcon,\n                    largeIcon: largeIcon,\n                    bigPicture: bigPicture,\n                    namePicture: pathPicture,\n                    repeat: repeat);\n            }\n        }\n\n        /// <summary>\n        /// Schedule notification with a custom delay time.\n        /// Used for scheduling notifications after app quit.\n        /// </summary>\n        public void ScheduleWithDelay(TimeSpan delay)\n        {\n            if (!Application.isMobilePlatform) return;\n            var data = datas.PickRandom();\n\n            string pathPicture = Path.Combine(Application.persistentDataPath, namePicture);\n\n            NotificationConsole.Schedule(identifier,\n                data.title,\n                data.message,\n                TimeSpan.FromMinutes(GetMinute()),\n                smallIcon: smallIcon,\n                largeIcon: largeIcon,\n                bigPicture: bigPicture,\n                namePicture: pathPicture,\n                repeat: false); // Không repeat khi schedule từ quit app\n        }\n\n        public void CancelAllScheduled()\n        {\n            if (!Application.isMobilePlatform) return;\n            NotificationConsole.CancelAllScheduled();\n        }\n\n        public void ClearBadgeCounterIOS()\n        {\n            if (!Application.isMobilePlatform) return;\n            NotificationConsole.ClearBadgeCounterIOS();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/NotificationVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4e085a2b84ef47babb9a940a1c0ead91\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 6a4b74d7042712c41acccbc6d90305fd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/virtuesky.sunflower.notifications.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Notifications\",\n    \"rootNamespace\": \"Virtuesky.Notifications\",\n    \"references\": [\n        \"GUID:ac145e6b8c6034cdbadc8c6e26aedbcf\",\n        \"GUID:1e8e55397bd004beaba78a667566665f\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:f51ebe6a0ceec4240a699833d6309b23\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:35d694408290717499b3838802212c7f\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [\n        {\n            \"name\": \"com.unity.mobile.notifications\",\n            \"expression\": \"2.2.2\",\n            \"define\": \"VIRTUESKY_NOTIFICATION\"\n        }\n    ],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Notifications/Runtime/virtuesky.sunflower.notifications.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 3aa1a48b88c8fc84ab64d4acf89d0b4e\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 4f687231ff0264b3996f6b0b445b6299\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Notifications.meta",
    "content": "fileFormatVersion: 2\nguid: 1e6ece33e35efd84180e34f52f349935\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ObjectPooling/Pool.cs",
    "content": "using UnityEngine;\n\nnamespace VirtueSky.ObjectPooling\n{\n    public static class Pool\n    {\n        private static PoolHandle _poolHandle;\n\n        public static void InitPool()\n        {\n            if (_poolHandle == null)\n            {\n                _poolHandle = new PoolHandle();\n                _poolHandle.Initialize();\n            }\n        }\n\n\n        #region API Spawn\n\n        public static void PreSpawn(this PoolData poolData)\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return;\n            }\n\n            _poolHandle.PreSpawn(poolData);\n        }\n\n        public static GameObject Spawn(this GameObject prefab, Transform parent = null, bool worldPositionStays = true,\n            bool initialize = true)\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return null;\n            }\n\n            return _poolHandle.Spawn(prefab, parent, worldPositionStays, initialize);\n        }\n\n        public static T Spawn<T>(this T type, Transform parent = null, bool worldPositionStays = true,\n            bool initialize = true) where T : Component\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return null;\n            }\n\n            return _poolHandle.Spawn(type, parent, worldPositionStays, initialize).GetComponent<T>();\n        }\n\n        public static GameObject Spawn(this GameObject prefab, Vector3 position, Quaternion rotation,\n            Transform parent = null,\n            bool worldPositionStays = true,\n            bool initialize = true)\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return null;\n            }\n\n            return _poolHandle.Spawn(prefab, position, rotation, parent, worldPositionStays, initialize);\n        }\n\n        public static T Spawn<T>(this T type, Vector3 position, Quaternion rotation, Transform parent = null,\n            bool worldPositionStays = true, bool initialize = true)\n            where T : Component\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return null;\n            }\n\n            return _poolHandle.Spawn(type, position, rotation, parent, worldPositionStays, initialize)\n                .GetComponent<T>();\n        }\n\n        #endregion\n\n        #region API DeSpawn\n\n        public static void DeSpawn(this GameObject gameObject, bool destroy = false, bool worldPositionStays = true)\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return;\n            }\n\n            _poolHandle.DeSpawn(gameObject, destroy, worldPositionStays);\n        }\n\n        public static void DeSpawn<T>(this T type, bool destroy = false, bool worldPositionStays = true)\n            where T : Component\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return;\n            }\n\n            _poolHandle.DeSpawn(type, destroy, worldPositionStays);\n        }\n\n        public static void DeSpawnAll()\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return;\n            }\n\n            _poolHandle.DeSpawnAll();\n        }\n\n        #endregion\n\n        #region API Destroy\n\n        public static void DestroyAll()\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return;\n            }\n\n            _poolHandle.DestroyAll();\n        }\n\n        public static void DestroyAllWaitPools()\n        {\n            if (_poolHandle == null)\n            {\n                Debug.Log($\"Please init pool before {System.Reflection.MethodBase.GetCurrentMethod()?.Name}\");\n                return;\n            }\n\n            _poolHandle.DestroyAllWaitPools();\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/ObjectPooling/Pool.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d45c7da498394701bdec5fc3d009c838\ntimeCreated: 1718288027"
  },
  {
    "path": "VirtueSky/ObjectPooling/PoolData.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.ObjectPooling\n{\n    [Serializable]\n    public class PoolData\n    {\n        public GameObject prefab;\n        public int count;\n    }\n}"
  },
  {
    "path": "VirtueSky/ObjectPooling/PoolData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2f523271ec3745128123b017c75e5da1\ntimeCreated: 1718287843"
  },
  {
    "path": "VirtueSky/ObjectPooling/PoolHandle.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\nusing UnityEngine.SceneManagement;\nusing VirtueSky.Core;\n#if UNITY_EDITOR\n#endif\n\nnamespace VirtueSky.ObjectPooling\n{\n    internal sealed class PoolHandle\n    {\n        private Dictionary<GameObject, Queue<GameObject>> waitPool;\n        private LinkedList<GameObject> activePool;\n        private Transform container;\n        private bool initialized;\n\n        internal void Initialize()\n        {\n            if (initialized) return;\n            initialized = true;\n\n            waitPool = new Dictionary<GameObject, Queue<GameObject>>();\n            activePool = new LinkedList<GameObject>();\n            container = new GameObject(\"PoolContainer\").transform;\n            UnityEngine.Object.DontDestroyOnLoad(container.gameObject);\n        }\n\n        internal void PreSpawn(PoolData poolData)\n        {\n            for (var i = 0; i < poolData.count; i++)\n            {\n                SpawnNew(poolData.prefab);\n            }\n        }\n\n        private void SpawnNew(GameObject prefab)\n        {\n            var gameObject = UnityEngine.Object.Instantiate(prefab);\n            var id = gameObject.AddComponent<PooledObjectId>();\n            id.prefab = prefab;\n\n            activePool.AddLast(gameObject);\n\n            DeSpawn(gameObject, false);\n        }\n\n        internal void DeSpawn<T>(T type, bool destroy = false, bool worldPositionStays = true) where T : Component\n        {\n            DeSpawn(type.gameObject, destroy, worldPositionStays);\n        }\n\n        internal void DeSpawn(GameObject gameObject, bool destroy = false, bool worldPositionStays = true)\n        {\n            var id = gameObject.GetComponent<PooledObjectId>();\n            if (id == null)\n            {\n                Debug.LogError($\"{gameObject.name} is not a pooled object!\");\n                return;\n            }\n\n            if (!activePool.Contains(gameObject))\n            {\n                Debug.LogError($\"{gameObject.name} is not in active pool!\");\n                return;\n            }\n\n            activePool.Remove(gameObject);\n            if (!waitPool.ContainsKey(id.prefab))\n            {\n                waitPool.Add(id.prefab, new Queue<GameObject>());\n            }\n\n            var stack = waitPool[id.prefab];\n            if (stack.Contains(gameObject))\n            {\n                Debug.LogError($\"{gameObject.name} is already pooled!\");\n                return;\n            }\n\n            CleanUp(gameObject);\n            if (destroy)\n            {\n                UnityEngine.Object.Destroy(gameObject);\n            }\n            else\n            {\n                gameObject.SetActive(false);\n                gameObject.transform.SetParent(container, worldPositionStays);\n                stack.Enqueue(gameObject);\n            }\n        }\n\n        internal void DeSpawnAll()\n        {\n            var arr = activePool.ToArray();\n            foreach (var o in arr)\n            {\n                if (o != null) DeSpawn(o);\n            }\n        }\n\n        internal void DestroyAllWaitPools()\n        {\n            foreach (var (key, queue) in waitPool)\n            {\n                foreach (var go in queue)\n                {\n                    CleanUp(go);\n                    UnityEngine.Object.DestroyImmediate(go);\n                }\n\n                queue.Clear();\n            }\n\n            waitPool.Clear();\n        }\n\n        internal void DestroyAll()\n        {\n            var arr = waitPool.Values.SelectMany(g => g).ToArray();\n            for (var i = 0; i < arr.Length; i++)\n            {\n                UnityEngine.Object.Destroy(arr[i].gameObject);\n            }\n\n            waitPool.Clear();\n        }\n\n        internal T Spawn<T>(T type, Transform parent = null, bool worldPositionStays = true, bool initialize = true)\n            where T : Component\n        {\n            return Spawn(type.gameObject, parent, worldPositionStays, initialize).GetComponent<T>();\n        }\n\n        internal GameObject Spawn(GameObject prefab, Transform parent = null, bool worldPositionStays = true,\n            bool initialize = true)\n        {\n            if (!waitPool.ContainsKey(prefab))\n            {\n                waitPool.Add(prefab, new Queue<GameObject>());\n            }\n\n            var stack = waitPool[prefab];\n            if (stack.Count == 0)\n            {\n                SpawnNew(prefab);\n            }\n\n            var gameObject = stack.Dequeue();\n\n            gameObject.transform.SetParent(parent, worldPositionStays);\n\n            if (parent == null)\n            {\n                SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());\n            }\n\n            gameObject.SetActive(true);\n\n            if (initialize)\n            {\n                InitializeObj(gameObject);\n            }\n\n            activePool.AddLast(gameObject);\n\n            return gameObject;\n        }\n\n        internal T Spawn<T>(T type, Vector3 position, Quaternion rotation, Transform parent = null,\n            bool worldPositionStays = true, bool initialize = true)\n            where T : Component\n        {\n            return Spawn(type.gameObject, position, rotation, parent, worldPositionStays, initialize).GetComponent<T>();\n        }\n\n        internal GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation, Transform parent = null,\n            bool worldPositionStays = true,\n            bool initialize = true)\n        {\n            if (!waitPool.ContainsKey(prefab))\n            {\n                waitPool.Add(prefab, new Queue<GameObject>());\n            }\n\n            var stack = waitPool[prefab];\n            if (stack.Count == 0)\n            {\n                SpawnNew(prefab);\n            }\n\n            var gameObject = stack.Dequeue();\n\n            gameObject.transform.SetParent(parent, worldPositionStays);\n            gameObject.transform.SetPositionAndRotation(position, rotation);\n\n            if (parent == null)\n            {\n                SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());\n            }\n\n            gameObject.SetActive(true);\n\n            if (initialize)\n            {\n                InitializeObj(gameObject);\n            }\n\n            activePool.AddLast(gameObject);\n\n            return gameObject;\n        }\n\n        void InitializeObj(GameObject go)\n        {\n            var monos = go.GetComponentsInChildren<BaseMono>(true);\n            foreach (var mono in monos)\n            {\n                mono.Initialize();\n            }\n        }\n\n        void CleanUp(GameObject go)\n        {\n            var monos = go.GetComponentsInChildren<BaseMono>(true);\n            foreach (var mono in monos)\n            {\n                mono.CleanUp();\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/ObjectPooling/PoolHandle.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ea56204fcdc152d4ba795117fd8fff72\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 9a1531ff57a958c4c92ab33ca22f62ef, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ObjectPooling/PooledObjectId.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.ObjectPooling\n{\n    public class PooledObjectId : MonoBehaviour\n    {\n        public GameObject prefab;\n    }\n}"
  },
  {
    "path": "VirtueSky/ObjectPooling/PooledObjectId.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: b5e68b9f9e9f478ab34ddf8bcde5baa3\ntimeCreated: 1652323347"
  },
  {
    "path": "VirtueSky/ObjectPooling/virtuesky.sunflower.objectpooling.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.ObjectPooling\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/ObjectPooling/virtuesky.sunflower.objectpooling.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: ce8c6e3f188ed064f933ef35b46bf8bd\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/ObjectPooling.meta",
    "content": "fileFormatVersion: 2\nguid: e935857045c5c7949b038f6337c22b52\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating/Editor/RatingWindowEditor.cs",
    "content": "using UnityEditor;\n\n\nnamespace VirtueSky.Rating\n{\n#if UNITY_EDITOR\n    using VirtueSky.UtilsEditor;\n\n    public class RatingWindowEditor : EditorWindow\n    {\n        #region In App Review\n\n        //  [MenuItem(\"Sunflower/InAppReview\")]\n        public static void CreateInAppReview()\n        {\n            CreateAsset.CreateScriptableAssets<InAppReview>(\"/InAppReview\", \"in_app_review\");\n        }\n\n        #endregion\n    }\n\n#endif\n}"
  },
  {
    "path": "VirtueSky/Rating/Editor/RatingWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9f3b777987e806743974099f2e64644d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating/Editor/Virtuesky.Sunflower.Rating.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Rating.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c1d20589f66abf146ba53fb06bf1e096\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Rating/Editor/Virtuesky.Sunflower.Rating.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 2e2b9634fb53a4c01af8453caa52e1b4\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 0f33de8e4e83ea6448fd8cda07165391\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating/Runtime/InAppReview.cs",
    "content": "﻿using VirtueSky.Inspector;\n\nnamespace VirtueSky.Rating\n{\n    using UnityEngine;\n    using System.Collections;\n    using VirtueSky.Core;\n\n#if UNITY_IOS\n     using UnityEngine.iOS;\n#elif UNITY_ANDROID && VIRTUESKY_RATING\n    using Google.Play.Review;\n#endif\n\n\n    [CreateAssetMenu(menuName = \"Sunflower/InAppReview\", fileName = \"in_app_review\")]\n    [EditorIcon(\"icon_scriptable\")]\n    public class InAppReview : ScriptableObject\n    {\n#if UNITY_ANDROID && VIRTUESKY_RATING\n        private ReviewManager _reviewManager;\n        private PlayReviewInfo _playReviewInfo;\n        private Coroutine _coroutine;\n#endif\n\n        public void InitInAppReview()\n        {\n            if (!Application.isMobilePlatform) return;\n#if UNITY_ANDROID && VIRTUESKY_RATING\n            _coroutine = App.StartCoroutine(InitReview());\n#endif\n        }\n\n        public void RateAndReview()\n        {\n            if (!Application.isMobilePlatform) return;\n\n#if UNITY_ANDROID && VIRTUESKY_RATING\n            App.StartCoroutine(LaunchReview());\n#elif UNITY_IOS\n            Device.RequestStoreReview();\n#endif\n        }\n\n#if UNITY_ANDROID && VIRTUESKY_RATING\n        private IEnumerator InitReview(bool force = false)\n        {\n            if (_reviewManager == null) _reviewManager = new ReviewManager();\n\n            var requestFlowOperation = _reviewManager.RequestReviewFlow();\n            yield return requestFlowOperation;\n            if (requestFlowOperation.Error != ReviewErrorCode.NoError)\n            {\n                if (force) DirectlyOpen();\n                yield break;\n            }\n\n            _playReviewInfo = requestFlowOperation.GetResult();\n        }\n\n        public IEnumerator LaunchReview()\n        {\n            if (_playReviewInfo == null)\n            {\n                if (_coroutine != null) App.StopCoroutine(_coroutine);\n                yield return App.StartCoroutine(InitReview(true));\n            }\n\n            var launchFlowOperation = _reviewManager.LaunchReviewFlow(_playReviewInfo);\n            yield return launchFlowOperation;\n            _playReviewInfo = null;\n            if (launchFlowOperation.Error != ReviewErrorCode.NoError)\n            {\n                DirectlyOpen();\n                yield break;\n            }\n        }\n#endif\n        private void DirectlyOpen()\n        {\n            Application.OpenURL($\"https://play.google.com/store/apps/details?id={Application.identifier}\");\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Rating/Runtime/InAppReview.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 538a395c127744f089e6bdf4a887a5f6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating/Runtime/virtuesky.sunflower.rating.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Rating\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:b4318b6f3695442c4983c360248781db\",\n        \"GUID:4139e191aa32f459e9eb2e331225ad7e\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Rating/Runtime/virtuesky.sunflower.rating.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: c1d20589f66abf146ba53fb06bf1e096\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: f9571eb1f2a824d9faed01d3af64a55b\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Rating.meta",
    "content": "﻿fileFormatVersion: 2\nguid: bfa984a0102e4ea5992ae004bda255e8\ntimeCreated: 1697010252"
  },
  {
    "path": "VirtueSky/RemoteConfig/FirebaseRemoteConfigData.cs",
    "content": "using System;\n\n#if VIRTUESKY_FIREBASE_REMOTECONFIG\nusing Firebase.RemoteConfig;\n#endif\n\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.RemoteConfigs\n{\n    [Serializable]\n    public class FirebaseRemoteConfigData\n    {\n        public string key;\n        public TypeRemoteConfigData typeRemoteConfigData;\n\n        [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.StringData)]\n        public StringVariable stringValue;\n\n        [GUIColor(0.8f, 1.0f, 0.6f)] [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.StringData)] [ReadOnly]\n        public string resultStringValue;\n\n\n        [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.BooleanData)]\n        public BooleanVariable boolValue;\n\n        [GUIColor(0.8f, 1.0f, 0.6f)] [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.BooleanData)] [ReadOnly]\n        public bool resultBoolValue;\n\n\n        [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.IntData)]\n        public IntegerVariable intValue;\n\n        [GUIColor(0.8f, 1.0f, 0.6f)] [ShowIf(nameof(typeRemoteConfigData), TypeRemoteConfigData.IntData)] [ReadOnly]\n        public int resultIntValue;\n\n\n#if VIRTUESKY_FIREBASE_REMOTECONFIG\n        public void SetUpData(ConfigValue result)\n        {\n            switch (typeRemoteConfigData)\n            {\n                case TypeRemoteConfigData.StringData:\n                    if (result.Source == ValueSource.RemoteValue)\n                    {\n                        stringValue.Value = result.StringValue;\n                    }\n\n                    resultStringValue = stringValue.Value;\n                    Debug.Log($\"{key}: {resultStringValue}\".SetColor(Color.green));\n                    break;\n                case TypeRemoteConfigData.BooleanData:\n                    if (result.Source == ValueSource.RemoteValue)\n                    {\n                        boolValue.Value = result.BooleanValue;\n                    }\n\n                    resultBoolValue = boolValue.Value;\n                    Debug.Log($\"{key}: {resultBoolValue}\".SetColor(Color.green));\n                    break;\n                case TypeRemoteConfigData.IntData:\n                    if (result.Source == ValueSource.RemoteValue)\n                    {\n                        intValue.Value = int.Parse(result.StringValue);\n                    }\n\n                    resultIntValue = intValue.Value;\n                    Debug.Log($\"{key}: {resultIntValue}\".SetColor(Color.green));\n                    break;\n            }\n        }\n#endif\n    }\n\n    public enum TypeRemoteConfigData\n    {\n        StringData,\n        BooleanData,\n        IntData\n    }\n}"
  },
  {
    "path": "VirtueSky/RemoteConfig/FirebaseRemoteConfigData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: bf53a27a63001b44cbf10dab99ed8d4c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/RemoteConfig/FirebaseRemoteConfigManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\n#if VIRTUESKY_FIREBASE\nusing Firebase;\nusing Firebase.Extensions;\n#endif\n#if VIRTUESKY_FIREBASE_REMOTECONFIG\nusing Firebase.RemoteConfig;\n#endif\n\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\nusing VirtueSky.Utils;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.RemoteConfigs\n{\n    [EditorIcon(\"icon_controller\"), HideMonoScript]\n    public class FirebaseRemoteConfigManager : MonoBehaviour\n    {\n        [SerializeField] private TypeInitRemoteConfig typeInitRemoteConfig;\n#if VIRTUESKY_FIREBASE\n        [Space, ReadOnly, SerializeField] private DependencyStatus dependencyStatus = DependencyStatus.UnavailableOther;\n#endif\n\n        [Space, SerializeField] private BooleanVariable isFetchRemoteConfigCompleted;\n        [Space, SerializeField] private BooleanVariable firebaseDependencyAvailable;\n        [Space, SerializeField] private FirebaseRemoteConfigData[] listRemoteConfigData;\n\n        private void Awake()\n        {\n            if (typeInitRemoteConfig == TypeInitRemoteConfig.InitOnAwake)\n            {\n                InitRemoteConfig();\n            }\n        }\n\n        private void Start()\n        {\n            if (typeInitRemoteConfig == TypeInitRemoteConfig.InitOnStart)\n            {\n                InitRemoteConfig();\n            }\n        }\n\n        private void InitRemoteConfig()\n        {\n#if VIRTUESKY_FIREBASE\n            if (isFetchRemoteConfigCompleted != null)\n            {\n                isFetchRemoteConfigCompleted.Value = false;\n            }\n\n            if (firebaseDependencyAvailable != null)\n            {\n                firebaseDependencyAvailable.Value = false;\n            }\n\n            FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>\n            {\n                dependencyStatus = task.Result;\n                if (dependencyStatus == DependencyStatus.Available)\n                {\n                    var app = FirebaseApp.DefaultInstance;\n                    if (firebaseDependencyAvailable != null)\n                    {\n                        firebaseDependencyAvailable.Value = true;\n                    }\n#if VIRTUESKY_FIREBASE_REMOTECONFIG\n                    FetchDataAsync();\n#endif\n                }\n                else\n                {\n                    Debug.LogError($\"Could not resolve all Firebase dependencies: {dependencyStatus}\".SetColor(Color.red));\n                }\n            });\n#endif\n        }\n\n#if VIRTUESKY_FIREBASE_REMOTECONFIG && VIRTUESKY_FIREBASE\n        public Task FetchDataAsync()\n        {\n            Debug.Log(\"Fetching data...\".SetColor(CustomColor.Cyan));\n            Task fetchTask = FirebaseRemoteConfig.DefaultInstance\n                .FetchAsync(TimeSpan.Zero);\n            return fetchTask.ContinueWithOnMainThread(tast =>\n            {\n                var info = FirebaseRemoteConfig.DefaultInstance.Info;\n                if (info.LastFetchStatus == LastFetchStatus.Success)\n                {\n                    FirebaseRemoteConfig.DefaultInstance.ActivateAsync().ContinueWithOnMainThread(\n                        task =>\n                        {\n                            Debug.Log(String.Format(\"Remote data loaded and ready (last fetch time {0}).\".SetColor(CustomColor.Cyan), info.FetchTime));\n                            foreach (var rmcData in listRemoteConfigData)\n                            {\n                                if (string.IsNullOrEmpty(rmcData.key) ||\n                                    (rmcData.typeRemoteConfigData == TypeRemoteConfigData.BooleanData &&\n                                     rmcData.boolValue == null) ||\n                                    (rmcData.typeRemoteConfigData == TypeRemoteConfigData.StringData &&\n                                     rmcData.stringValue == null) ||\n                                    (rmcData.typeRemoteConfigData == TypeRemoteConfigData.IntData &&\n                                     rmcData.intValue == null)) continue;\n\n                                rmcData.SetUpData(FirebaseRemoteConfig.DefaultInstance\n                                    .GetValue(rmcData.key));\n                            }\n\n                            if (isFetchRemoteConfigCompleted != null)\n                            {\n                                isFetchRemoteConfigCompleted.Value = true;\n                            }\n                        });\n\n                    Debug.Log(\"Firebase Remote Config Fetching completed!\".SetColor(Color.green));\n                }\n                else\n                {\n                    Debug.Log(\"Fetching data did not completed!\".SetColor(Color.red));\n                }\n            });\n        }\n#endif\n    }\n\n    enum TypeInitRemoteConfig\n    {\n        InitOnAwake,\n        InitOnStart\n    }\n}"
  },
  {
    "path": "VirtueSky/RemoteConfig/FirebaseRemoteConfigManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e909f45ff43f51f4eafa07ac90416b0b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/RemoteConfig/Virtuesky.Sunflower.RemoteConfigs.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.RemoteConfigs\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:35d694408290717499b3838802212c7f\",\n        \"GUID:fca7ec166e04dc948b624a983315e2c9\",\n        \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/RemoteConfig/Virtuesky.Sunflower.RemoteConfigs.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 8825d2918c76a804eb16e58185f7e6d3\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/RemoteConfig.meta",
    "content": "fileFormatVersion: 2\nguid: 77ac67b0da2cc6d4dbf0b969a97276ec\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSON.cs",
    "content": "/* * * * *\n * A simple JSON Parser / builder\n * ------------------------------\n *\n * It mainly has been written as a simple JSON parser. It can build a JSON string\n * from the node-tree, or generate a node tree from any valid JSON string.\n *\n * Written by Bunny83\n * 2012-06-09\n *\n * Changelog now external. See Changelog.txt\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2012-2022 Markus Göbel (Bunny83)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * * * * */\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\n\nnamespace VirtueSky.SimpleJSON\n{\n    public enum JSONNodeType\n    {\n        Array = 1,\n        Object = 2,\n        String = 3,\n        Number = 4,\n        NullValue = 5,\n        Boolean = 6,\n        None = 7,\n        Custom = 0xFF,\n    }\n\n    public enum JSONTextMode\n    {\n        Compact,\n        Indent\n    }\n\n    public abstract partial class JSONNode\n    {\n        #region Enumerators\n\n        public struct Enumerator\n        {\n            private enum Type\n            {\n                None,\n                Array,\n                Object\n            }\n\n            private Type type;\n            private Dictionary<string, JSONNode>.Enumerator m_Object;\n            private List<JSONNode>.Enumerator m_Array;\n\n            public bool IsValid\n            {\n                get { return type != Type.None; }\n            }\n\n            public Enumerator(List<JSONNode>.Enumerator aArrayEnum)\n            {\n                type = Type.Array;\n                m_Object = default(Dictionary<string, JSONNode>.Enumerator);\n                m_Array = aArrayEnum;\n            }\n\n            public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)\n            {\n                type = Type.Object;\n                m_Object = aDictEnum;\n                m_Array = default(List<JSONNode>.Enumerator);\n            }\n\n            public KeyValuePair<string, JSONNode> Current\n            {\n                get\n                {\n                    if (type == Type.Array)\n                        return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current);\n                    else if (type == Type.Object)\n                        return m_Object.Current;\n                    return new KeyValuePair<string, JSONNode>(string.Empty, null);\n                }\n            }\n\n            public bool MoveNext()\n            {\n                if (type == Type.Array)\n                    return m_Array.MoveNext();\n                else if (type == Type.Object)\n                    return m_Object.MoveNext();\n                return false;\n            }\n        }\n\n        public struct ValueEnumerator\n        {\n            private Enumerator m_Enumerator;\n\n            public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(\n                new Enumerator(aArrayEnum))\n            {\n            }\n\n            public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(\n                new Enumerator(aDictEnum))\n            {\n            }\n\n            public ValueEnumerator(Enumerator aEnumerator)\n            {\n                m_Enumerator = aEnumerator;\n            }\n\n            public JSONNode Current\n            {\n                get { return m_Enumerator.Current.Value; }\n            }\n\n            public bool MoveNext()\n            {\n                return m_Enumerator.MoveNext();\n            }\n\n            public ValueEnumerator GetEnumerator()\n            {\n                return this;\n            }\n        }\n\n        public struct KeyEnumerator\n        {\n            private Enumerator m_Enumerator;\n\n            public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(\n                new Enumerator(aArrayEnum))\n            {\n            }\n\n            public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(\n                new Enumerator(aDictEnum))\n            {\n            }\n\n            public KeyEnumerator(Enumerator aEnumerator)\n            {\n                m_Enumerator = aEnumerator;\n            }\n\n            public string Current\n            {\n                get { return m_Enumerator.Current.Key; }\n            }\n\n            public bool MoveNext()\n            {\n                return m_Enumerator.MoveNext();\n            }\n\n            public KeyEnumerator GetEnumerator()\n            {\n                return this;\n            }\n        }\n\n        public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>,\n            IEnumerable<KeyValuePair<string, JSONNode>>\n        {\n            private JSONNode m_Node;\n            private Enumerator m_Enumerator;\n\n            internal LinqEnumerator(JSONNode aNode)\n            {\n                m_Node = aNode;\n                if (m_Node != null)\n                    m_Enumerator = m_Node.GetEnumerator();\n            }\n\n            public KeyValuePair<string, JSONNode> Current\n            {\n                get { return m_Enumerator.Current; }\n            }\n\n            object IEnumerator.Current\n            {\n                get { return m_Enumerator.Current; }\n            }\n\n            public bool MoveNext()\n            {\n                return m_Enumerator.MoveNext();\n            }\n\n            public void Dispose()\n            {\n                m_Node = null;\n                m_Enumerator = new Enumerator();\n            }\n\n            public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()\n            {\n                return new LinqEnumerator(m_Node);\n            }\n\n            public void Reset()\n            {\n                if (m_Node != null)\n                    m_Enumerator = m_Node.GetEnumerator();\n            }\n\n            IEnumerator IEnumerable.GetEnumerator()\n            {\n                return new LinqEnumerator(m_Node);\n            }\n        }\n\n        #endregion Enumerators\n\n        #region common interface\n\n        public static bool forceASCII = false; // Use Unicode by default\n\n        public static bool\n            longAsString = false; // lazy creator creates a JSONString instead of JSONNumber\n\n        public static bool\n            allowLineComments = true; // allow \"//\"-style comments at the end of a line\n\n        public abstract JSONNodeType Tag { get; }\n\n        public virtual JSONNode this[int aIndex]\n        {\n            get { return null; }\n            set { }\n        }\n\n        public virtual JSONNode this[string aKey]\n        {\n            get { return null; }\n            set { }\n        }\n\n        public virtual string Value\n        {\n            get { return \"\"; }\n            set { }\n        }\n\n        public virtual int Count\n        {\n            get { return 0; }\n        }\n\n        public virtual bool IsNumber\n        {\n            get { return false; }\n        }\n\n        public virtual bool IsString\n        {\n            get { return false; }\n        }\n\n        public virtual bool IsBoolean\n        {\n            get { return false; }\n        }\n\n        public virtual bool IsNull\n        {\n            get { return false; }\n        }\n\n        public virtual bool IsArray\n        {\n            get { return false; }\n        }\n\n        public virtual bool IsObject\n        {\n            get { return false; }\n        }\n\n        public virtual bool Inline\n        {\n            get { return false; }\n            set { }\n        }\n\n        public virtual void Add(string aKey, JSONNode aItem)\n        {\n        }\n\n        public virtual void Add(JSONNode aItem)\n        {\n            Add(\"\", aItem);\n        }\n\n        public virtual JSONNode Remove(string aKey)\n        {\n            return null;\n        }\n\n        public virtual JSONNode Remove(int aIndex)\n        {\n            return null;\n        }\n\n        public virtual JSONNode Remove(JSONNode aNode)\n        {\n            return aNode;\n        }\n\n        public virtual void Clear()\n        {\n        }\n\n        public virtual JSONNode Clone()\n        {\n            return null;\n        }\n\n        public virtual IEnumerable<JSONNode> Children\n        {\n            get { yield break; }\n        }\n\n        public IEnumerable<JSONNode> DeepChildren\n        {\n            get\n            {\n                foreach (var C in Children)\n                foreach (var D in C.DeepChildren)\n                    yield return D;\n            }\n        }\n\n        public virtual bool HasKey(string aKey)\n        {\n            return false;\n        }\n\n        public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)\n        {\n            return aDefault;\n        }\n\n        public override string ToString()\n        {\n            StringBuilder sb = new StringBuilder();\n            WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact);\n            return sb.ToString();\n        }\n\n        public virtual string ToString(int aIndent)\n        {\n            StringBuilder sb = new StringBuilder();\n            WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent);\n            return sb.ToString();\n        }\n\n        internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode);\n\n        public abstract Enumerator GetEnumerator();\n\n        public IEnumerable<KeyValuePair<string, JSONNode>> Linq\n        {\n            get { return new LinqEnumerator(this); }\n        }\n\n        public KeyEnumerator Keys\n        {\n            get { return new KeyEnumerator(GetEnumerator()); }\n        }\n\n        public ValueEnumerator Values\n        {\n            get { return new ValueEnumerator(GetEnumerator()); }\n        }\n\n        #endregion common interface\n\n        #region typecasting properties\n\n        public virtual double AsDouble\n        {\n            get\n            {\n                double v = 0.0;\n                if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))\n                    return v;\n                return 0.0;\n            }\n            set { Value = value.ToString(CultureInfo.InvariantCulture); }\n        }\n\n        public virtual int AsInt\n        {\n            get { return (int)AsDouble; }\n            set { AsDouble = value; }\n        }\n\n        public virtual float AsFloat\n        {\n            get { return (float)AsDouble; }\n            set { AsDouble = value; }\n        }\n\n        public virtual bool AsBool\n        {\n            get\n            {\n                bool v = false;\n                if (bool.TryParse(Value, out v))\n                    return v;\n                return !string.IsNullOrEmpty(Value);\n            }\n            set { Value = (value) ? \"true\" : \"false\"; }\n        }\n\n        public virtual long AsLong\n        {\n            get\n            {\n                long val = 0;\n                if (long.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture,\n                        out val))\n                    return val;\n                return 0L;\n            }\n            set { Value = value.ToString(CultureInfo.InvariantCulture); }\n        }\n\n        public virtual ulong AsULong\n        {\n            get\n            {\n                ulong val = 0;\n                if (ulong.TryParse(Value, NumberStyles.Integer, CultureInfo.InvariantCulture,\n                        out val))\n                    return val;\n                return 0;\n            }\n            set { Value = value.ToString(CultureInfo.InvariantCulture); }\n        }\n\n        public virtual JSONArray AsArray\n        {\n            get { return this as JSONArray; }\n        }\n\n        public virtual JSONObject AsObject\n        {\n            get { return this as JSONObject; }\n        }\n\n        #endregion typecasting properties\n\n        #region operators\n\n        public static implicit operator JSONNode(string s)\n        {\n            return (s == null) ? (JSONNode)JSONNull.CreateOrGet() : new JSONString(s);\n        }\n\n        public static implicit operator string(JSONNode d)\n        {\n            return (d == null) ? null : d.Value;\n        }\n\n        public static implicit operator JSONNode(double n)\n        {\n            return new JSONNumber(n);\n        }\n\n        public static implicit operator double(JSONNode d)\n        {\n            return (d == null) ? 0 : d.AsDouble;\n        }\n\n        public static implicit operator JSONNode(float n)\n        {\n            return new JSONNumber(n);\n        }\n\n        public static implicit operator float(JSONNode d)\n        {\n            return (d == null) ? 0 : d.AsFloat;\n        }\n\n        public static implicit operator JSONNode(int n)\n        {\n            return new JSONNumber(n);\n        }\n\n        public static implicit operator int(JSONNode d)\n        {\n            return (d == null) ? 0 : d.AsInt;\n        }\n\n        public static implicit operator JSONNode(long n)\n        {\n            if (longAsString)\n                return new JSONString(n.ToString(CultureInfo.InvariantCulture));\n            return new JSONNumber(n);\n        }\n\n        public static implicit operator long(JSONNode d)\n        {\n            return (d == null) ? 0L : d.AsLong;\n        }\n\n        public static implicit operator JSONNode(ulong n)\n        {\n            if (longAsString)\n                return new JSONString(n.ToString(CultureInfo.InvariantCulture));\n            return new JSONNumber(n);\n        }\n\n        public static implicit operator ulong(JSONNode d)\n        {\n            return (d == null) ? 0 : d.AsULong;\n        }\n\n        public static implicit operator JSONNode(bool b)\n        {\n            return new JSONBool(b);\n        }\n\n        public static implicit operator bool(JSONNode d)\n        {\n            return (d == null) ? false : d.AsBool;\n        }\n\n        public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue)\n        {\n            return aKeyValue.Value;\n        }\n\n        public static bool operator ==(JSONNode a, object b)\n        {\n            if (ReferenceEquals(a, b))\n                return true;\n            bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator;\n            bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator;\n            if (aIsNull && bIsNull)\n                return true;\n            return !aIsNull && a.Equals(b);\n        }\n\n        public static bool operator !=(JSONNode a, object b)\n        {\n            return !(a == b);\n        }\n\n        public override bool Equals(object obj)\n        {\n            return ReferenceEquals(this, obj);\n        }\n\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n\n        #endregion operators\n\n        [ThreadStatic] private static StringBuilder m_EscapeBuilder;\n\n        internal static StringBuilder EscapeBuilder\n        {\n            get\n            {\n                if (m_EscapeBuilder == null)\n                    m_EscapeBuilder = new StringBuilder();\n                return m_EscapeBuilder;\n            }\n        }\n\n        internal static string Escape(string aText)\n        {\n            var sb = EscapeBuilder;\n            sb.Length = 0;\n            if (sb.Capacity < aText.Length + aText.Length / 10)\n                sb.Capacity = aText.Length + aText.Length / 10;\n            foreach (char c in aText)\n            {\n                switch (c)\n                {\n                    case '\\\\':\n                        sb.Append(\"\\\\\\\\\");\n                        break;\n                    case '\\\"':\n                        sb.Append(\"\\\\\\\"\");\n                        break;\n                    case '\\n':\n                        sb.Append(\"\\\\n\");\n                        break;\n                    case '\\r':\n                        sb.Append(\"\\\\r\");\n                        break;\n                    case '\\t':\n                        sb.Append(\"\\\\t\");\n                        break;\n                    case '\\b':\n                        sb.Append(\"\\\\b\");\n                        break;\n                    case '\\f':\n                        sb.Append(\"\\\\f\");\n                        break;\n                    default:\n                        if (c < ' ' || (forceASCII && c > 127))\n                        {\n                            ushort val = c;\n                            sb.Append(\"\\\\u\").Append(val.ToString(\"X4\"));\n                        }\n                        else\n                            sb.Append(c);\n\n                        break;\n                }\n            }\n\n            string result = sb.ToString();\n            sb.Length = 0;\n            return result;\n        }\n\n        private static JSONNode ParseElement(string token, bool quoted)\n        {\n            if (quoted)\n                return token;\n            if (token.Length <= 5)\n            {\n                string tmp = token.ToLower();\n                if (tmp == \"false\" || tmp == \"true\")\n                    return tmp == \"true\";\n                if (tmp == \"null\")\n                    return JSONNull.CreateOrGet();\n            }\n\n            double val;\n            if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val))\n                return val;\n            else\n                return token;\n        }\n\n        public static JSONNode Parse(string aJSON)\n        {\n            Stack<JSONNode> stack = new Stack<JSONNode>();\n            JSONNode ctx = null;\n            int i = 0;\n            StringBuilder Token = new StringBuilder();\n            string TokenName = \"\";\n            bool QuoteMode = false;\n            bool TokenIsQuoted = false;\n            bool HasNewlineChar = false;\n            while (i < aJSON.Length)\n            {\n                switch (aJSON[i])\n                {\n                    case '{':\n                        if (QuoteMode)\n                        {\n                            Token.Append(aJSON[i]);\n                            break;\n                        }\n\n                        stack.Push(new JSONObject());\n                        if (ctx != null)\n                        {\n                            ctx.Add(TokenName, stack.Peek());\n                        }\n\n                        TokenName = \"\";\n                        Token.Length = 0;\n                        ctx = stack.Peek();\n                        HasNewlineChar = false;\n                        break;\n\n                    case '[':\n                        if (QuoteMode)\n                        {\n                            Token.Append(aJSON[i]);\n                            break;\n                        }\n\n                        stack.Push(new JSONArray());\n                        if (ctx != null)\n                        {\n                            ctx.Add(TokenName, stack.Peek());\n                        }\n\n                        TokenName = \"\";\n                        Token.Length = 0;\n                        ctx = stack.Peek();\n                        HasNewlineChar = false;\n                        break;\n\n                    case '}':\n                    case ']':\n                        if (QuoteMode)\n                        {\n                            Token.Append(aJSON[i]);\n                            break;\n                        }\n\n                        if (stack.Count == 0)\n                            throw new Exception(\"JSON Parse: Too many closing brackets\");\n\n                        stack.Pop();\n                        if (Token.Length > 0 || TokenIsQuoted)\n                            ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));\n                        if (ctx != null)\n                            ctx.Inline = !HasNewlineChar;\n                        TokenIsQuoted = false;\n                        TokenName = \"\";\n                        Token.Length = 0;\n                        if (stack.Count > 0)\n                            ctx = stack.Peek();\n                        break;\n\n                    case ':':\n                        if (QuoteMode)\n                        {\n                            Token.Append(aJSON[i]);\n                            break;\n                        }\n\n                        TokenName = Token.ToString();\n                        Token.Length = 0;\n                        TokenIsQuoted = false;\n                        break;\n\n                    case '\"':\n                        QuoteMode ^= true;\n                        TokenIsQuoted |= QuoteMode;\n                        break;\n\n                    case ',':\n                        if (QuoteMode)\n                        {\n                            Token.Append(aJSON[i]);\n                            break;\n                        }\n\n                        if (Token.Length > 0 || TokenIsQuoted)\n                            ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));\n                        TokenIsQuoted = false;\n                        TokenName = \"\";\n                        Token.Length = 0;\n                        TokenIsQuoted = false;\n                        break;\n\n                    case '\\r':\n                    case '\\n':\n                        HasNewlineChar = true;\n                        break;\n\n                    case ' ':\n                    case '\\t':\n                        if (QuoteMode)\n                            Token.Append(aJSON[i]);\n                        break;\n\n                    case '\\\\':\n                        ++i;\n                        if (QuoteMode)\n                        {\n                            char C = aJSON[i];\n                            switch (C)\n                            {\n                                case 't':\n                                    Token.Append('\\t');\n                                    break;\n                                case 'r':\n                                    Token.Append('\\r');\n                                    break;\n                                case 'n':\n                                    Token.Append('\\n');\n                                    break;\n                                case 'b':\n                                    Token.Append('\\b');\n                                    break;\n                                case 'f':\n                                    Token.Append('\\f');\n                                    break;\n                                case 'u':\n                                {\n                                    string s = aJSON.Substring(i + 1, 4);\n                                    Token.Append((char)int.Parse(\n                                        s,\n                                        System.Globalization.NumberStyles.AllowHexSpecifier));\n                                    i += 4;\n                                    break;\n                                }\n                                default:\n                                    Token.Append(C);\n                                    break;\n                            }\n                        }\n\n                        break;\n                    case '/':\n                        if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length &&\n                            aJSON[i + 1] == '/')\n                        {\n                            while (++i < aJSON.Length && aJSON[i] != '\\n' && aJSON[i] != '\\r') ;\n                            break;\n                        }\n\n                        Token.Append(aJSON[i]);\n                        break;\n                    case '\\uFEFF': // remove / ignore BOM (Byte Order Mark)\n                        break;\n\n                    default:\n                        Token.Append(aJSON[i]);\n                        break;\n                }\n\n                ++i;\n            }\n\n            if (QuoteMode)\n            {\n                throw new Exception(\"JSON Parse: Quotation marks seems to be messed up.\");\n            }\n\n            if (ctx == null)\n                return ParseElement(Token.ToString(), TokenIsQuoted);\n            return ctx;\n        }\n    }\n    // End of JSONNode\n\n    public partial class JSONArray : JSONNode\n    {\n        private List<JSONNode> m_List = new List<JSONNode>();\n        private bool inline = false;\n\n        public override bool Inline\n        {\n            get { return inline; }\n            set { inline = value; }\n        }\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.Array; }\n        }\n\n        public override bool IsArray\n        {\n            get { return true; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator(m_List.GetEnumerator());\n        }\n\n        public override JSONNode this[int aIndex]\n        {\n            get\n            {\n                if (aIndex < 0 || aIndex >= m_List.Count)\n                    return new JSONLazyCreator(this);\n                return m_List[aIndex];\n            }\n            set\n            {\n                if (value == null)\n                    value = JSONNull.CreateOrGet();\n                if (aIndex < 0 || aIndex >= m_List.Count)\n                    m_List.Add(value);\n                else\n                    m_List[aIndex] = value;\n            }\n        }\n\n        public override JSONNode this[string aKey]\n        {\n            get { return new JSONLazyCreator(this); }\n            set\n            {\n                if (value == null)\n                    value = JSONNull.CreateOrGet();\n                m_List.Add(value);\n            }\n        }\n\n        public override int Count\n        {\n            get { return m_List.Count; }\n        }\n\n        public override void Add(string aKey, JSONNode aItem)\n        {\n            if (aItem == null)\n                aItem = JSONNull.CreateOrGet();\n            m_List.Add(aItem);\n        }\n\n        public override JSONNode Remove(int aIndex)\n        {\n            if (aIndex < 0 || aIndex >= m_List.Count)\n                return null;\n            JSONNode tmp = m_List[aIndex];\n            m_List.RemoveAt(aIndex);\n            return tmp;\n        }\n\n        public override JSONNode Remove(JSONNode aNode)\n        {\n            m_List.Remove(aNode);\n            return aNode;\n        }\n\n        public override void Clear()\n        {\n            m_List.Clear();\n        }\n\n        public override JSONNode Clone()\n        {\n            var node = new JSONArray();\n            node.m_List.Capacity = m_List.Capacity;\n            foreach (var n in m_List)\n            {\n                if (n != null)\n                    node.Add(n.Clone());\n                else\n                    node.Add(null);\n            }\n\n            return node;\n        }\n\n        public override IEnumerable<JSONNode> Children\n        {\n            get\n            {\n                foreach (JSONNode N in m_List)\n                    yield return N;\n            }\n        }\n\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append('[');\n            int count = m_List.Count;\n            if (inline)\n                aMode = JSONTextMode.Compact;\n            for (int i = 0; i < count; i++)\n            {\n                if (i > 0)\n                    aSB.Append(',');\n                if (aMode == JSONTextMode.Indent)\n                    aSB.AppendLine();\n\n                if (aMode == JSONTextMode.Indent)\n                    aSB.Append(' ', aIndent + aIndentInc);\n                m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);\n            }\n\n            if (aMode == JSONTextMode.Indent)\n                aSB.AppendLine().Append(' ', aIndent);\n            aSB.Append(']');\n        }\n    }\n    // End of JSONArray\n\n    public partial class JSONObject : JSONNode\n    {\n        private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>();\n\n        private bool inline = false;\n\n        public override bool Inline\n        {\n            get { return inline; }\n            set { inline = value; }\n        }\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.Object; }\n        }\n\n        public override bool IsObject\n        {\n            get { return true; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator(m_Dict.GetEnumerator());\n        }\n\n\n        public override JSONNode this[string aKey]\n        {\n            get\n            {\n                if (m_Dict.ContainsKey(aKey))\n                    return m_Dict[aKey];\n                else\n                    return new JSONLazyCreator(this, aKey);\n            }\n            set\n            {\n                if (value == null)\n                    value = JSONNull.CreateOrGet();\n                if (m_Dict.ContainsKey(aKey))\n                    m_Dict[aKey] = value;\n                else\n                    m_Dict.Add(aKey, value);\n            }\n        }\n\n        public override JSONNode this[int aIndex]\n        {\n            get\n            {\n                if (aIndex < 0 || aIndex >= m_Dict.Count)\n                    return null;\n                return m_Dict.ElementAt(aIndex).Value;\n            }\n            set\n            {\n                if (value == null)\n                    value = JSONNull.CreateOrGet();\n                if (aIndex < 0 || aIndex >= m_Dict.Count)\n                    return;\n                string key = m_Dict.ElementAt(aIndex).Key;\n                m_Dict[key] = value;\n            }\n        }\n\n        public override int Count\n        {\n            get { return m_Dict.Count; }\n        }\n\n        public override void Add(string aKey, JSONNode aItem)\n        {\n            if (aItem == null)\n                aItem = JSONNull.CreateOrGet();\n\n            if (aKey != null)\n            {\n                if (m_Dict.ContainsKey(aKey))\n                    m_Dict[aKey] = aItem;\n                else\n                    m_Dict.Add(aKey, aItem);\n            }\n            else\n                m_Dict.Add(Guid.NewGuid().ToString(), aItem);\n        }\n\n        public override JSONNode Remove(string aKey)\n        {\n            if (!m_Dict.ContainsKey(aKey))\n                return null;\n            JSONNode tmp = m_Dict[aKey];\n            m_Dict.Remove(aKey);\n            return tmp;\n        }\n\n        public override JSONNode Remove(int aIndex)\n        {\n            if (aIndex < 0 || aIndex >= m_Dict.Count)\n                return null;\n            var item = m_Dict.ElementAt(aIndex);\n            m_Dict.Remove(item.Key);\n            return item.Value;\n        }\n\n        public override JSONNode Remove(JSONNode aNode)\n        {\n            try\n            {\n                var item = m_Dict.Where(k => k.Value == aNode).First();\n                m_Dict.Remove(item.Key);\n                return aNode;\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        public override void Clear()\n        {\n            m_Dict.Clear();\n        }\n\n        public override JSONNode Clone()\n        {\n            var node = new JSONObject();\n            foreach (var n in m_Dict)\n            {\n                node.Add(n.Key, n.Value.Clone());\n            }\n\n            return node;\n        }\n\n        public override bool HasKey(string aKey)\n        {\n            return m_Dict.ContainsKey(aKey);\n        }\n\n        public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)\n        {\n            JSONNode res;\n            if (m_Dict.TryGetValue(aKey, out res))\n                return res;\n            return aDefault;\n        }\n\n        public override IEnumerable<JSONNode> Children\n        {\n            get\n            {\n                foreach (KeyValuePair<string, JSONNode> N in m_Dict)\n                    yield return N.Value;\n            }\n        }\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append('{');\n            bool first = true;\n            if (inline)\n                aMode = JSONTextMode.Compact;\n            foreach (var k in m_Dict)\n            {\n                if (!first)\n                    aSB.Append(',');\n                first = false;\n                if (aMode == JSONTextMode.Indent)\n                    aSB.AppendLine();\n                if (aMode == JSONTextMode.Indent)\n                    aSB.Append(' ', aIndent + aIndentInc);\n                aSB.Append('\\\"').Append(Escape(k.Key)).Append('\\\"');\n                if (aMode == JSONTextMode.Compact)\n                    aSB.Append(':');\n                else\n                    aSB.Append(\" : \");\n                k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);\n            }\n\n            if (aMode == JSONTextMode.Indent)\n                aSB.AppendLine().Append(' ', aIndent);\n            aSB.Append('}');\n        }\n    }\n    // End of JSONObject\n\n    public partial class JSONString : JSONNode\n    {\n        private string m_Data;\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.String; }\n        }\n\n        public override bool IsString\n        {\n            get { return true; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator();\n        }\n\n\n        public override string Value\n        {\n            get { return m_Data; }\n            set { m_Data = value; }\n        }\n\n        public JSONString(string aData)\n        {\n            m_Data = aData;\n        }\n\n        public override JSONNode Clone()\n        {\n            return new JSONString(m_Data);\n        }\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append('\\\"').Append(Escape(m_Data)).Append('\\\"');\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (base.Equals(obj))\n                return true;\n            string s = obj as string;\n            if (s != null)\n                return m_Data == s;\n            JSONString s2 = obj as JSONString;\n            if (s2 != null)\n                return m_Data == s2.m_Data;\n            return false;\n        }\n\n        public override int GetHashCode()\n        {\n            return m_Data.GetHashCode();\n        }\n\n        public override void Clear()\n        {\n            m_Data = \"\";\n        }\n    }\n    // End of JSONString\n\n    public partial class JSONNumber : JSONNode\n    {\n        private double m_Data;\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.Number; }\n        }\n\n        public override bool IsNumber\n        {\n            get { return true; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator();\n        }\n\n        public override string Value\n        {\n            get { return m_Data.ToString(CultureInfo.InvariantCulture); }\n            set\n            {\n                double v;\n                if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))\n                    m_Data = v;\n            }\n        }\n\n        public override double AsDouble\n        {\n            get { return m_Data; }\n            set { m_Data = value; }\n        }\n\n        public override long AsLong\n        {\n            get { return (long)m_Data; }\n            set { m_Data = value; }\n        }\n\n        public override ulong AsULong\n        {\n            get { return (ulong)m_Data; }\n            set { m_Data = value; }\n        }\n\n        public JSONNumber(double aData)\n        {\n            m_Data = aData;\n        }\n\n        public JSONNumber(string aData)\n        {\n            Value = aData;\n        }\n\n        public override JSONNode Clone()\n        {\n            return new JSONNumber(m_Data);\n        }\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append(Value.ToString(CultureInfo.InvariantCulture));\n        }\n\n        private static bool IsNumeric(object value)\n        {\n            return value is int || value is uint\n                                || value is float || value is double\n                                || value is decimal\n                                || value is long || value is ulong\n                                || value is short || value is ushort\n                                || value is sbyte || value is byte;\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (obj == null)\n                return false;\n            if (base.Equals(obj))\n                return true;\n            JSONNumber s2 = obj as JSONNumber;\n            if (s2 != null)\n                return m_Data == s2.m_Data;\n            if (IsNumeric(obj))\n                return Convert.ToDouble(obj) == m_Data;\n            return false;\n        }\n\n        public override int GetHashCode()\n        {\n            return m_Data.GetHashCode();\n        }\n\n        public override void Clear()\n        {\n            m_Data = 0;\n        }\n    }\n    // End of JSONNumber\n\n    public partial class JSONBool : JSONNode\n    {\n        private bool m_Data;\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.Boolean; }\n        }\n\n        public override bool IsBoolean\n        {\n            get { return true; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator();\n        }\n\n        public override string Value\n        {\n            get { return m_Data.ToString(); }\n            set\n            {\n                bool v;\n                if (bool.TryParse(value, out v))\n                    m_Data = v;\n            }\n        }\n\n        public override bool AsBool\n        {\n            get { return m_Data; }\n            set { m_Data = value; }\n        }\n\n        public JSONBool(bool aData)\n        {\n            m_Data = aData;\n        }\n\n        public JSONBool(string aData)\n        {\n            Value = aData;\n        }\n\n        public override JSONNode Clone()\n        {\n            return new JSONBool(m_Data);\n        }\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append((m_Data) ? \"true\" : \"false\");\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (obj == null)\n                return false;\n            if (obj is bool)\n                return m_Data == (bool)obj;\n            return false;\n        }\n\n        public override int GetHashCode()\n        {\n            return m_Data.GetHashCode();\n        }\n\n        public override void Clear()\n        {\n            m_Data = false;\n        }\n    }\n    // End of JSONBool\n\n    public partial class JSONNull : JSONNode\n    {\n        static JSONNull m_StaticInstance = new JSONNull();\n        public static bool reuseSameInstance = true;\n\n        public static JSONNull CreateOrGet()\n        {\n            if (reuseSameInstance)\n                return m_StaticInstance;\n            return new JSONNull();\n        }\n\n        private JSONNull()\n        {\n        }\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.NullValue; }\n        }\n\n        public override bool IsNull\n        {\n            get { return true; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator();\n        }\n\n        public override string Value\n        {\n            get { return \"null\"; }\n            set { }\n        }\n\n        public override bool AsBool\n        {\n            get { return false; }\n            set { }\n        }\n\n        public override JSONNode Clone()\n        {\n            return CreateOrGet();\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (object.ReferenceEquals(this, obj))\n                return true;\n            return (obj is JSONNull);\n        }\n\n        public override int GetHashCode()\n        {\n            return 0;\n        }\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append(\"null\");\n        }\n    }\n    // End of JSONNull\n\n    internal partial class JSONLazyCreator : JSONNode\n    {\n        private JSONNode m_Node = null;\n        private string m_Key = null;\n\n        public override JSONNodeType Tag\n        {\n            get { return JSONNodeType.None; }\n        }\n\n        public override Enumerator GetEnumerator()\n        {\n            return new Enumerator();\n        }\n\n        public JSONLazyCreator(JSONNode aNode)\n        {\n            m_Node = aNode;\n            m_Key = null;\n        }\n\n        public JSONLazyCreator(JSONNode aNode, string aKey)\n        {\n            m_Node = aNode;\n            m_Key = aKey;\n        }\n\n        private T Set<T>(T aVal) where T : JSONNode\n        {\n            if (m_Key == null)\n                m_Node.Add(aVal);\n            else\n                m_Node.Add(m_Key, aVal);\n            m_Node = null; // Be GC friendly.\n            return aVal;\n        }\n\n        public override JSONNode this[int aIndex]\n        {\n            get { return new JSONLazyCreator(this); }\n            set { Set(new JSONArray()).Add(value); }\n        }\n\n        public override JSONNode this[string aKey]\n        {\n            get { return new JSONLazyCreator(this, aKey); }\n            set { Set(new JSONObject()).Add(aKey, value); }\n        }\n\n        public override void Add(JSONNode aItem)\n        {\n            Set(new JSONArray()).Add(aItem);\n        }\n\n        public override void Add(string aKey, JSONNode aItem)\n        {\n            Set(new JSONObject()).Add(aKey, aItem);\n        }\n\n        public static bool operator ==(JSONLazyCreator a, object b)\n        {\n            if (b == null)\n                return true;\n            return System.Object.ReferenceEquals(a, b);\n        }\n\n        public static bool operator !=(JSONLazyCreator a, object b)\n        {\n            return !(a == b);\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (obj == null)\n                return true;\n            return System.Object.ReferenceEquals(this, obj);\n        }\n\n        public override int GetHashCode()\n        {\n            return 0;\n        }\n\n        public override int AsInt\n        {\n            get\n            {\n                Set(new JSONNumber(0));\n                return 0;\n            }\n            set { Set(new JSONNumber(value)); }\n        }\n\n        public override float AsFloat\n        {\n            get\n            {\n                Set(new JSONNumber(0.0f));\n                return 0.0f;\n            }\n            set { Set(new JSONNumber(value)); }\n        }\n\n        public override double AsDouble\n        {\n            get\n            {\n                Set(new JSONNumber(0.0));\n                return 0.0;\n            }\n            set { Set(new JSONNumber(value)); }\n        }\n\n        public override long AsLong\n        {\n            get\n            {\n                if (longAsString)\n                    Set(new JSONString(\"0\"));\n                else\n                    Set(new JSONNumber(0.0));\n                return 0L;\n            }\n            set\n            {\n                if (longAsString)\n                    Set(new JSONString(value.ToString(CultureInfo.InvariantCulture)));\n                else\n                    Set(new JSONNumber(value));\n            }\n        }\n\n        public override ulong AsULong\n        {\n            get\n            {\n                if (longAsString)\n                    Set(new JSONString(\"0\"));\n                else\n                    Set(new JSONNumber(0.0));\n                return 0L;\n            }\n            set\n            {\n                if (longAsString)\n                    Set(new JSONString(value.ToString(CultureInfo.InvariantCulture)));\n                else\n                    Set(new JSONNumber(value));\n            }\n        }\n\n        public override bool AsBool\n        {\n            get\n            {\n                Set(new JSONBool(false));\n                return false;\n            }\n            set { Set(new JSONBool(value)); }\n        }\n\n        public override JSONArray AsArray\n        {\n            get { return Set(new JSONArray()); }\n        }\n\n        public override JSONObject AsObject\n        {\n            get { return Set(new JSONObject()); }\n        }\n\n        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc,\n            JSONTextMode aMode)\n        {\n            aSB.Append(\"null\");\n        }\n    }\n    // End of JSONLazyCreator\n\n    public static class JSON\n    {\n        public static JSONNode Parse(string aJSON)\n        {\n            return JSONNode.Parse(aJSON);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSON.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e5263f587bfd4e440aba9b1b9996004c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSONBinary.cs",
    "content": "//#define USE_SharpZipLib\n/* * * * *\n * This is an extension of the SimpleJSON framework to provide methods to\n * serialize a JSON object tree into a compact binary format. Optionally the\n * binary stream can be compressed with the SharpZipLib when using the define\n * \"USE_SharpZipLib\"\n *\n * Those methods where originally part of the framework but since it's rarely\n * used I've extracted this part into this seperate module file.\n *\n * You can use the define \"SimpleJSON_ExcludeBinary\" to selectively disable\n * this extension without the need to remove the file from the project.\n *\n * If you want to use compression when saving to file / stream / B64 you have to include\n * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and\n * define \"USE_SharpZipLib\" at the top of the file\n *\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2012-2017 Markus Göbel (Bunny83)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * * * * */\n\nusing System;\n\nnamespace VirtueSky.SimpleJSON\n{\n#if !SimpleJSON_ExcludeBinary\n    public abstract partial class JSONNode\n    {\n        public abstract void SerializeBinary(System.IO.BinaryWriter aWriter);\n\n        public void SaveToBinaryStream(System.IO.Stream aData)\n        {\n            var W = new System.IO.BinaryWriter(aData);\n            SerializeBinary(W);\n        }\n\n#if USE_SharpZipLib\n\t\tpublic void SaveToCompressedStream(System.IO.Stream aData)\n\t\t{\n\t\t\tusing (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData))\n\t\t\t{\n\t\t\t\tgzipOut.IsStreamOwner = false;\n\t\t\t\tSaveToBinaryStream(gzipOut);\n\t\t\t\tgzipOut.Close();\n\t\t\t}\n\t\t}\n \n\t\tpublic void SaveToCompressedFile(string aFileName)\n\t\t{\n \n\t\t\tSystem.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName);\n\t\t\tusing(var F = System.IO.File.OpenWrite(aFileName))\n\t\t\t{\n\t\t\t\tSaveToCompressedStream(F);\n\t\t\t}\n\t\t}\n\t\tpublic string SaveToCompressedBase64()\n\t\t{\n\t\t\tusing (var stream = new System.IO.MemoryStream())\n\t\t\t{\n\t\t\t\tSaveToCompressedStream(stream);\n\t\t\t\tstream.Position = 0;\n\t\t\t\treturn System.Convert.ToBase64String(stream.ToArray());\n\t\t\t}\n\t\t}\n\n#else\n        public void SaveToCompressedStream(System.IO.Stream aData)\n        {\n            throw new Exception(\n                \"Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON\");\n        }\n\n        public void SaveToCompressedFile(string aFileName)\n        {\n            throw new Exception(\n                \"Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON\");\n        }\n\n        public string SaveToCompressedBase64()\n        {\n            throw new Exception(\n                \"Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON\");\n        }\n#endif\n\n        public void SaveToBinaryFile(string aFileName)\n        {\n            System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory\n                .FullName);\n            using (var F = System.IO.File.OpenWrite(aFileName))\n            {\n                SaveToBinaryStream(F);\n            }\n        }\n\n        public string SaveToBinaryBase64()\n        {\n            using (var stream = new System.IO.MemoryStream())\n            {\n                SaveToBinaryStream(stream);\n                stream.Position = 0;\n                return System.Convert.ToBase64String(stream.ToArray());\n            }\n        }\n\n        public static JSONNode DeserializeBinary(System.IO.BinaryReader aReader)\n        {\n            JSONNodeType type = (JSONNodeType)aReader.ReadByte();\n            switch (type)\n            {\n                case JSONNodeType.Array:\n                {\n                    int count = aReader.ReadInt32();\n                    JSONArray tmp = new JSONArray();\n                    for (int i = 0; i < count; i++)\n                        tmp.Add(DeserializeBinary(aReader));\n                    return tmp;\n                }\n                case JSONNodeType.Object:\n                {\n                    int count = aReader.ReadInt32();\n                    JSONObject tmp = new JSONObject();\n                    for (int i = 0; i < count; i++)\n                    {\n                        string key = aReader.ReadString();\n                        var val = DeserializeBinary(aReader);\n                        tmp.Add(key, val);\n                    }\n\n                    return tmp;\n                }\n                case JSONNodeType.String:\n                {\n                    return new JSONString(aReader.ReadString());\n                }\n                case JSONNodeType.Number:\n                {\n                    return new JSONNumber(aReader.ReadDouble());\n                }\n                case JSONNodeType.Boolean:\n                {\n                    return new JSONBool(aReader.ReadBoolean());\n                }\n                case JSONNodeType.NullValue:\n                {\n                    return JSONNull.CreateOrGet();\n                }\n                default:\n                {\n                    throw new Exception(\"Error deserializing JSON. Unknown tag: \" + type);\n                }\n            }\n        }\n\n#if USE_SharpZipLib\n\t\tpublic static JSONNode LoadFromCompressedStream(System.IO.Stream aData)\n\t\t{\n\t\t\tvar zin = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(aData);\n\t\t\treturn LoadFromBinaryStream(zin);\n\t\t}\n\t\tpublic static JSONNode LoadFromCompressedFile(string aFileName)\n\t\t{\n\t\t\tusing(var F = System.IO.File.OpenRead(aFileName))\n\t\t\t{\n\t\t\t\treturn LoadFromCompressedStream(F);\n\t\t\t}\n\t\t}\n\t\tpublic static JSONNode LoadFromCompressedBase64(string aBase64)\n\t\t{\n\t\t\tvar tmp = System.Convert.FromBase64String(aBase64);\n\t\t\tvar stream = new System.IO.MemoryStream(tmp);\n\t\t\tstream.Position = 0;\n\t\t\treturn LoadFromCompressedStream(stream);\n\t\t}\n#else\n        public static JSONNode LoadFromCompressedFile(string aFileName)\n        {\n            throw new Exception(\n                \"Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON\");\n        }\n\n        public static JSONNode LoadFromCompressedStream(System.IO.Stream aData)\n        {\n            throw new Exception(\n                \"Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON\");\n        }\n\n        public static JSONNode LoadFromCompressedBase64(string aBase64)\n        {\n            throw new Exception(\n                \"Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON\");\n        }\n#endif\n\n        public static JSONNode LoadFromBinaryStream(System.IO.Stream aData)\n        {\n            using (var R = new System.IO.BinaryReader(aData))\n            {\n                return DeserializeBinary(R);\n            }\n        }\n\n        public static JSONNode LoadFromBinaryFile(string aFileName)\n        {\n            using (var F = System.IO.File.OpenRead(aFileName))\n            {\n                return LoadFromBinaryStream(F);\n            }\n        }\n\n        public static JSONNode LoadFromBinaryBase64(string aBase64)\n        {\n            var tmp = System.Convert.FromBase64String(aBase64);\n            var stream = new System.IO.MemoryStream(tmp);\n            stream.Position = 0;\n            return LoadFromBinaryStream(stream);\n        }\n    }\n\n    public partial class JSONArray : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n            aWriter.Write((byte)JSONNodeType.Array);\n            aWriter.Write(m_List.Count);\n            for (int i = 0; i < m_List.Count; i++)\n            {\n                m_List[i].SerializeBinary(aWriter);\n            }\n        }\n    }\n\n    public partial class JSONObject : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n            aWriter.Write((byte)JSONNodeType.Object);\n            aWriter.Write(m_Dict.Count);\n            foreach (string K in m_Dict.Keys)\n            {\n                aWriter.Write(K);\n                m_Dict[K].SerializeBinary(aWriter);\n            }\n        }\n    }\n\n    public partial class JSONString : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n            aWriter.Write((byte)JSONNodeType.String);\n            aWriter.Write(m_Data);\n        }\n    }\n\n    public partial class JSONNumber : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n            aWriter.Write((byte)JSONNodeType.Number);\n            aWriter.Write(m_Data);\n        }\n    }\n\n    public partial class JSONBool : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n            aWriter.Write((byte)JSONNodeType.Boolean);\n            aWriter.Write(m_Data);\n        }\n    }\n\n    public partial class JSONNull : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n            aWriter.Write((byte)JSONNodeType.NullValue);\n        }\n    }\n\n    internal partial class JSONLazyCreator : JSONNode\n    {\n        public override void SerializeBinary(System.IO.BinaryWriter aWriter)\n        {\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSONBinary.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 49ead892e1332124380a7d5e810b51af\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSONDotNetTypes.cs",
    "content": "﻿#region License and information\n\n/* * * * *\n *\n * Extension file for the SimpleJSON framework for better support of some common\n * .NET types. It does only work together with the SimpleJSON.cs\n * It provides direct conversion support for types like decimal, char, byte,\n * sbyte, short, ushort, uint, DateTime, TimeSpan and Guid. In addition there\n * are conversion helpers for converting an array of number values into a byte[]\n * or a List<byte> as well as converting an array of string values into a string[]\n * or List<string>.\n * Finally there are some additional type conversion operators for some nullable\n * types like short?, int?, float?, double?, long? and bool?. They will actually\n * assign a JSONNull value when it's null or a JSONNumber when it's not.\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2020 Markus Göbel (Bunny83)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * * * * */\n\n#endregion License and information\n\nnamespace VirtueSky.SimpleJSON\n{\n    using System.Globalization;\n    using System.Collections.Generic;\n\n    public partial class JSONNode\n    {\n        #region Decimal\n\n        public virtual decimal AsDecimal\n        {\n            get\n            {\n                decimal result;\n                if (!decimal.TryParse(Value, out result))\n                    result = 0;\n                return result;\n            }\n            set { Value = value.ToString(); }\n        }\n\n        public static implicit operator JSONNode(decimal aDecimal)\n        {\n            return new JSONString(aDecimal.ToString());\n        }\n\n        public static implicit operator decimal(JSONNode aNode)\n        {\n            return aNode.AsDecimal;\n        }\n\n        #endregion Decimal\n\n        #region Char\n\n        public virtual char AsChar\n        {\n            get\n            {\n                if (IsString && Value.Length > 0)\n                    return Value[0];\n                if (IsNumber)\n                    return (char)AsInt;\n                return '\\0';\n            }\n            set\n            {\n                if (IsString)\n                    Value = value.ToString();\n                else if (IsNumber)\n                    AsInt = (int)value;\n            }\n        }\n\n        public static implicit operator JSONNode(char aChar)\n        {\n            return new JSONString(aChar.ToString());\n        }\n\n        public static implicit operator char(JSONNode aNode)\n        {\n            return aNode.AsChar;\n        }\n\n        #endregion Decimal\n\n        #region UInt\n\n        public virtual uint AsUInt\n        {\n            get { return (uint)AsDouble; }\n            set { AsDouble = value; }\n        }\n\n        public static implicit operator JSONNode(uint aUInt)\n        {\n            return new JSONNumber(aUInt);\n        }\n\n        public static implicit operator uint(JSONNode aNode)\n        {\n            return aNode.AsUInt;\n        }\n\n        #endregion UInt\n\n        #region Byte\n\n        public virtual byte AsByte\n        {\n            get { return (byte)AsInt; }\n            set { AsInt = value; }\n        }\n\n        public static implicit operator JSONNode(byte aByte)\n        {\n            return new JSONNumber(aByte);\n        }\n\n        public static implicit operator byte(JSONNode aNode)\n        {\n            return aNode.AsByte;\n        }\n\n        #endregion Byte\n\n        #region SByte\n\n        public virtual sbyte AsSByte\n        {\n            get { return (sbyte)AsInt; }\n            set { AsInt = value; }\n        }\n\n        public static implicit operator JSONNode(sbyte aSByte)\n        {\n            return new JSONNumber(aSByte);\n        }\n\n        public static implicit operator sbyte(JSONNode aNode)\n        {\n            return aNode.AsSByte;\n        }\n\n        #endregion SByte\n\n        #region Short\n\n        public virtual short AsShort\n        {\n            get { return (short)AsInt; }\n            set { AsInt = value; }\n        }\n\n        public static implicit operator JSONNode(short aShort)\n        {\n            return new JSONNumber(aShort);\n        }\n\n        public static implicit operator short(JSONNode aNode)\n        {\n            return aNode.AsShort;\n        }\n\n        #endregion Short\n\n        #region UShort\n\n        public virtual ushort AsUShort\n        {\n            get { return (ushort)AsInt; }\n            set { AsInt = value; }\n        }\n\n        public static implicit operator JSONNode(ushort aUShort)\n        {\n            return new JSONNumber(aUShort);\n        }\n\n        public static implicit operator ushort(JSONNode aNode)\n        {\n            return aNode.AsUShort;\n        }\n\n        #endregion UShort\n\n        #region DateTime\n\n        public virtual System.DateTime AsDateTime\n        {\n            get\n            {\n                System.DateTime result;\n                if (!System.DateTime.TryParse(Value, CultureInfo.InvariantCulture,\n                        DateTimeStyles.None, out result))\n                    result = new System.DateTime(0);\n                return result;\n            }\n            set { Value = value.ToString(CultureInfo.InvariantCulture); }\n        }\n\n        public static implicit operator JSONNode(System.DateTime aDateTime)\n        {\n            return new JSONString(aDateTime.ToString(CultureInfo.InvariantCulture));\n        }\n\n        public static implicit operator System.DateTime(JSONNode aNode)\n        {\n            return aNode.AsDateTime;\n        }\n\n        #endregion DateTime\n\n        #region TimeSpan\n\n        public virtual System.TimeSpan AsTimeSpan\n        {\n            get\n            {\n                System.TimeSpan result;\n                if (!System.TimeSpan.TryParse(Value, CultureInfo.InvariantCulture, out result))\n                    result = new System.TimeSpan(0);\n                return result;\n            }\n            set { Value = value.ToString(); }\n        }\n\n        public static implicit operator JSONNode(System.TimeSpan aTimeSpan)\n        {\n            return new JSONString(aTimeSpan.ToString());\n        }\n\n        public static implicit operator System.TimeSpan(JSONNode aNode)\n        {\n            return aNode.AsTimeSpan;\n        }\n\n        #endregion TimeSpan\n\n        #region Guid\n\n        public virtual System.Guid AsGuid\n        {\n            get\n            {\n                System.Guid result;\n                System.Guid.TryParse(Value, out result);\n                return result;\n            }\n            set { Value = value.ToString(); }\n        }\n\n        public static implicit operator JSONNode(System.Guid aGuid)\n        {\n            return new JSONString(aGuid.ToString());\n        }\n\n        public static implicit operator System.Guid(JSONNode aNode)\n        {\n            return aNode.AsGuid;\n        }\n\n        #endregion Guid\n\n        #region ByteArray\n\n        public virtual byte[] AsByteArray\n        {\n            get\n            {\n                if (this.IsNull || !this.IsArray)\n                    return null;\n                int count = Count;\n                byte[] result = new byte[count];\n                for (int i = 0; i < count; i++)\n                    result[i] = this[i].AsByte;\n                return result;\n            }\n            set\n            {\n                if (!IsArray || value == null)\n                    return;\n                Clear();\n                for (int i = 0; i < value.Length; i++)\n                    Add(value[i]);\n            }\n        }\n\n        public static implicit operator JSONNode(byte[] aByteArray)\n        {\n            return new JSONArray { AsByteArray = aByteArray };\n        }\n\n        public static implicit operator byte[](JSONNode aNode)\n        {\n            return aNode.AsByteArray;\n        }\n\n        #endregion ByteArray\n\n        #region ByteList\n\n        public virtual List<byte> AsByteList\n        {\n            get\n            {\n                if (this.IsNull || !this.IsArray)\n                    return null;\n                int count = Count;\n                List<byte> result = new List<byte>(count);\n                for (int i = 0; i < count; i++)\n                    result.Add(this[i].AsByte);\n                return result;\n            }\n            set\n            {\n                if (!IsArray || value == null)\n                    return;\n                Clear();\n                for (int i = 0; i < value.Count; i++)\n                    Add(value[i]);\n            }\n        }\n\n        public static implicit operator JSONNode(List<byte> aByteList)\n        {\n            return new JSONArray { AsByteList = aByteList };\n        }\n\n        public static implicit operator List<byte>(JSONNode aNode)\n        {\n            return aNode.AsByteList;\n        }\n\n        #endregion ByteList\n\n        #region StringArray\n\n        public virtual string[] AsStringArray\n        {\n            get\n            {\n                if (this.IsNull || !this.IsArray)\n                    return null;\n                int count = Count;\n                string[] result = new string[count];\n                for (int i = 0; i < count; i++)\n                    result[i] = this[i].Value;\n                return result;\n            }\n            set\n            {\n                if (!IsArray || value == null)\n                    return;\n                Clear();\n                for (int i = 0; i < value.Length; i++)\n                    Add(value[i]);\n            }\n        }\n\n        public static implicit operator JSONNode(string[] aStringArray)\n        {\n            return new JSONArray { AsStringArray = aStringArray };\n        }\n\n        public static implicit operator string[](JSONNode aNode)\n        {\n            return aNode.AsStringArray;\n        }\n\n        #endregion StringArray\n\n        #region StringList\n\n        public virtual List<string> AsStringList\n        {\n            get\n            {\n                if (this.IsNull || !this.IsArray)\n                    return null;\n                int count = Count;\n                List<string> result = new List<string>(count);\n                for (int i = 0; i < count; i++)\n                    result.Add(this[i].Value);\n                return result;\n            }\n            set\n            {\n                if (!IsArray || value == null)\n                    return;\n                Clear();\n                for (int i = 0; i < value.Count; i++)\n                    Add(value[i]);\n            }\n        }\n\n        public static implicit operator JSONNode(List<string> aStringList)\n        {\n            return new JSONArray { AsStringList = aStringList };\n        }\n\n        public static implicit operator List<string>(JSONNode aNode)\n        {\n            return aNode.AsStringList;\n        }\n\n        #endregion StringList\n\n        #region NullableTypes\n\n        public static implicit operator JSONNode(int? aValue)\n        {\n            if (aValue == null)\n                return JSONNull.CreateOrGet();\n            return new JSONNumber((int)aValue);\n        }\n\n        public static implicit operator int?(JSONNode aNode)\n        {\n            if (aNode == null || aNode.IsNull)\n                return null;\n            return aNode.AsInt;\n        }\n\n        public static implicit operator JSONNode(float? aValue)\n        {\n            if (aValue == null)\n                return JSONNull.CreateOrGet();\n            return new JSONNumber((float)aValue);\n        }\n\n        public static implicit operator float?(JSONNode aNode)\n        {\n            if (aNode == null || aNode.IsNull)\n                return null;\n            return aNode.AsFloat;\n        }\n\n        public static implicit operator JSONNode(double? aValue)\n        {\n            if (aValue == null)\n                return JSONNull.CreateOrGet();\n            return new JSONNumber((double)aValue);\n        }\n\n        public static implicit operator double?(JSONNode aNode)\n        {\n            if (aNode == null || aNode.IsNull)\n                return null;\n            return aNode.AsDouble;\n        }\n\n        public static implicit operator JSONNode(bool? aValue)\n        {\n            if (aValue == null)\n                return JSONNull.CreateOrGet();\n            return new JSONBool((bool)aValue);\n        }\n\n        public static implicit operator bool?(JSONNode aNode)\n        {\n            if (aNode == null || aNode.IsNull)\n                return null;\n            return aNode.AsBool;\n        }\n\n        public static implicit operator JSONNode(long? aValue)\n        {\n            if (aValue == null)\n                return JSONNull.CreateOrGet();\n            return new JSONNumber((long)aValue);\n        }\n\n        public static implicit operator long?(JSONNode aNode)\n        {\n            if (aNode == null || aNode.IsNull)\n                return null;\n            return aNode.AsLong;\n        }\n\n        public static implicit operator JSONNode(short? aValue)\n        {\n            if (aValue == null)\n                return JSONNull.CreateOrGet();\n            return new JSONNumber((short)aValue);\n        }\n\n        public static implicit operator short?(JSONNode aNode)\n        {\n            if (aNode == null || aNode.IsNull)\n                return null;\n            return aNode.AsShort;\n        }\n\n        #endregion NullableTypes\n    }\n}"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSONDotNetTypes.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e1f66c32e2f2f89448cff7c8a69c768d\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSONUnity.cs",
    "content": "#if UNITY_5_3_OR_NEWER\n\n#region License and information\n\n/* * * * *\n *\n * Unity extension for the SimpleJSON framework. It does only work together with\n * the SimpleJSON.cs\n * It provides several helpers and conversion operators to serialize/deserialize\n * common Unity types such as Vector2/3/4, Rect, RectOffset, Quaternion and\n * Matrix4x4 as JSONObject or JSONArray.\n * This extension will add 3 static settings to the JSONNode class:\n * ( VectorContainerType, QuaternionContainerType, RectContainerType ) which\n * control what node type should be used for serializing the given type. So a\n * Vector3 as array would look like [12,32,24] and {\"x\":12, \"y\":32, \"z\":24} as\n * object.\n *\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2012-2017 Markus Göbel (Bunny83)\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * * * * */\n\n#endregion License and information\n\nusing UnityEngine;\n\nnamespace VirtueSky.SimpleJSON\n{\n    public enum JSONContainerType\n    {\n        Array,\n        Object\n    }\n\n    public partial class JSONNode\n    {\n        public static byte Color32DefaultAlpha = 255;\n        public static float ColorDefaultAlpha = 1f;\n        public static JSONContainerType VectorContainerType = JSONContainerType.Array;\n        public static JSONContainerType QuaternionContainerType = JSONContainerType.Array;\n        public static JSONContainerType RectContainerType = JSONContainerType.Array;\n        public static JSONContainerType ColorContainerType = JSONContainerType.Array;\n\n        private static JSONNode GetContainer(JSONContainerType aType)\n        {\n            if (aType == JSONContainerType.Array)\n                return new JSONArray();\n            return new JSONObject();\n        }\n\n        #region implicit conversion operators\n\n        public static implicit operator JSONNode(Vector2 aVec)\n        {\n            JSONNode n = GetContainer(VectorContainerType);\n            n.WriteVector2(aVec);\n            return n;\n        }\n\n        public static implicit operator JSONNode(Vector3 aVec)\n        {\n            JSONNode n = GetContainer(VectorContainerType);\n            n.WriteVector3(aVec);\n            return n;\n        }\n\n        public static implicit operator JSONNode(Vector4 aVec)\n        {\n            JSONNode n = GetContainer(VectorContainerType);\n            n.WriteVector4(aVec);\n            return n;\n        }\n\n        public static implicit operator JSONNode(Color aCol)\n        {\n            JSONNode n = GetContainer(ColorContainerType);\n            n.WriteColor(aCol);\n            return n;\n        }\n\n        public static implicit operator JSONNode(Color32 aCol)\n        {\n            JSONNode n = GetContainer(ColorContainerType);\n            n.WriteColor32(aCol);\n            return n;\n        }\n\n        public static implicit operator JSONNode(Quaternion aRot)\n        {\n            JSONNode n = GetContainer(QuaternionContainerType);\n            n.WriteQuaternion(aRot);\n            return n;\n        }\n\n        public static implicit operator JSONNode(Rect aRect)\n        {\n            JSONNode n = GetContainer(RectContainerType);\n            n.WriteRect(aRect);\n            return n;\n        }\n\n        public static implicit operator JSONNode(RectOffset aRect)\n        {\n            JSONNode n = GetContainer(RectContainerType);\n            n.WriteRectOffset(aRect);\n            return n;\n        }\n\n        public static implicit operator Vector2(JSONNode aNode)\n        {\n            return aNode.ReadVector2();\n        }\n\n        public static implicit operator Vector3(JSONNode aNode)\n        {\n            return aNode.ReadVector3();\n        }\n\n        public static implicit operator Vector4(JSONNode aNode)\n        {\n            return aNode.ReadVector4();\n        }\n\n        public static implicit operator Color(JSONNode aNode)\n        {\n            return aNode.ReadColor();\n        }\n\n        public static implicit operator Color32(JSONNode aNode)\n        {\n            return aNode.ReadColor32();\n        }\n\n        public static implicit operator Quaternion(JSONNode aNode)\n        {\n            return aNode.ReadQuaternion();\n        }\n\n        public static implicit operator Rect(JSONNode aNode)\n        {\n            return aNode.ReadRect();\n        }\n\n        public static implicit operator RectOffset(JSONNode aNode)\n        {\n            return aNode.ReadRectOffset();\n        }\n\n        #endregion implicit conversion operators\n\n        #region Vector2\n\n        public Vector2 ReadVector2(Vector2 aDefault)\n        {\n            if (IsObject)\n                return new Vector2(this[\"x\"].AsFloat, this[\"y\"].AsFloat);\n            if (IsArray)\n                return new Vector2(this[0].AsFloat, this[1].AsFloat);\n            return aDefault;\n        }\n\n        public Vector2 ReadVector2(string aXName, string aYName)\n        {\n            if (IsObject)\n            {\n                return new Vector2(this[aXName].AsFloat, this[aYName].AsFloat);\n            }\n\n            return Vector2.zero;\n        }\n\n        public Vector2 ReadVector2()\n        {\n            return ReadVector2(Vector2.zero);\n        }\n\n        public JSONNode WriteVector2(Vector2 aVec, string aXName = \"x\", string aYName = \"y\")\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[aXName].AsFloat = aVec.x;\n                this[aYName].AsFloat = aVec.y;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsFloat = aVec.x;\n                this[1].AsFloat = aVec.y;\n            }\n\n            return this;\n        }\n\n        #endregion Vector2\n\n        #region Vector3\n\n        public Vector3 ReadVector3(Vector3 aDefault)\n        {\n            if (IsObject)\n                return new Vector3(this[\"x\"].AsFloat, this[\"y\"].AsFloat, this[\"z\"].AsFloat);\n            if (IsArray)\n                return new Vector3(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat);\n            return aDefault;\n        }\n\n        public Vector3 ReadVector3(string aXName, string aYName, string aZName)\n        {\n            if (IsObject)\n                return new Vector3(this[aXName].AsFloat, this[aYName].AsFloat,\n                    this[aZName].AsFloat);\n            return Vector3.zero;\n        }\n\n        public Vector3 ReadVector3()\n        {\n            return ReadVector3(Vector3.zero);\n        }\n\n        public JSONNode WriteVector3(Vector3 aVec, string aXName = \"x\", string aYName = \"y\",\n            string aZName = \"z\")\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[aXName].AsFloat = aVec.x;\n                this[aYName].AsFloat = aVec.y;\n                this[aZName].AsFloat = aVec.z;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsFloat = aVec.x;\n                this[1].AsFloat = aVec.y;\n                this[2].AsFloat = aVec.z;\n            }\n\n            return this;\n        }\n\n        #endregion Vector3\n\n        #region Vector4\n\n        public Vector4 ReadVector4(Vector4 aDefault)\n        {\n            if (IsObject)\n                return new Vector4(this[\"x\"].AsFloat, this[\"y\"].AsFloat, this[\"z\"].AsFloat,\n                    this[\"w\"].AsFloat);\n            if (IsArray)\n                return new Vector4(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat,\n                    this[3].AsFloat);\n            return aDefault;\n        }\n\n        public Vector4 ReadVector4()\n        {\n            return ReadVector4(Vector4.zero);\n        }\n\n        public JSONNode WriteVector4(Vector4 aVec)\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[\"x\"].AsFloat = aVec.x;\n                this[\"y\"].AsFloat = aVec.y;\n                this[\"z\"].AsFloat = aVec.z;\n                this[\"w\"].AsFloat = aVec.w;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsFloat = aVec.x;\n                this[1].AsFloat = aVec.y;\n                this[2].AsFloat = aVec.z;\n                this[3].AsFloat = aVec.w;\n            }\n\n            return this;\n        }\n\n        #endregion Vector4\n\n        #region Color / Color32\n\n        public Color ReadColor(Color aDefault)\n        {\n            if (IsObject)\n                return new Color(this[\"r\"].AsFloat, this[\"g\"].AsFloat, this[\"b\"].AsFloat,\n                    HasKey(\"a\") ? this[\"a\"].AsFloat : ColorDefaultAlpha);\n            if (IsArray)\n                return new Color(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat,\n                    (Count > 3) ? this[3].AsFloat : ColorDefaultAlpha);\n            return aDefault;\n        }\n\n        public Color ReadColor()\n        {\n            return ReadColor(Color.clear);\n        }\n\n        public JSONNode WriteColor(Color aCol)\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[\"r\"].AsFloat = aCol.r;\n                this[\"g\"].AsFloat = aCol.g;\n                this[\"b\"].AsFloat = aCol.b;\n                this[\"a\"].AsFloat = aCol.a;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsFloat = aCol.r;\n                this[1].AsFloat = aCol.g;\n                this[2].AsFloat = aCol.b;\n                this[3].AsFloat = aCol.a;\n            }\n\n            return this;\n        }\n\n        public Color32 ReadColor32(Color32 aDefault)\n        {\n            if (IsObject)\n                return new Color32((byte)this[\"r\"].AsInt, (byte)this[\"g\"].AsInt,\n                    (byte)this[\"b\"].AsInt,\n                    (byte)(HasKey(\"a\") ? this[\"a\"].AsInt : Color32DefaultAlpha));\n            if (IsArray)\n                return new Color32((byte)this[0].AsInt, (byte)this[1].AsInt, (byte)this[2].AsInt,\n                    (byte)((Count > 3) ? this[3].AsInt : Color32DefaultAlpha));\n            return aDefault;\n        }\n\n        public Color32 ReadColor32()\n        {\n            return ReadColor32(new Color32());\n        }\n\n        public JSONNode WriteColor32(Color32 aCol)\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[\"r\"].AsInt = aCol.r;\n                this[\"g\"].AsInt = aCol.g;\n                this[\"b\"].AsInt = aCol.b;\n                this[\"a\"].AsInt = aCol.a;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsInt = aCol.r;\n                this[1].AsInt = aCol.g;\n                this[2].AsInt = aCol.b;\n                this[3].AsInt = aCol.a;\n            }\n\n            return this;\n        }\n\n        #endregion Color / Color32\n\n        #region Quaternion\n\n        public Quaternion ReadQuaternion(Quaternion aDefault)\n        {\n            if (IsObject)\n                return new Quaternion(this[\"x\"].AsFloat, this[\"y\"].AsFloat, this[\"z\"].AsFloat,\n                    this[\"w\"].AsFloat);\n            if (IsArray)\n                return new Quaternion(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat,\n                    this[3].AsFloat);\n            return aDefault;\n        }\n\n        public Quaternion ReadQuaternion()\n        {\n            return ReadQuaternion(Quaternion.identity);\n        }\n\n        public JSONNode WriteQuaternion(Quaternion aRot)\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[\"x\"].AsFloat = aRot.x;\n                this[\"y\"].AsFloat = aRot.y;\n                this[\"z\"].AsFloat = aRot.z;\n                this[\"w\"].AsFloat = aRot.w;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsFloat = aRot.x;\n                this[1].AsFloat = aRot.y;\n                this[2].AsFloat = aRot.z;\n                this[3].AsFloat = aRot.w;\n            }\n\n            return this;\n        }\n\n        #endregion Quaternion\n\n        #region Rect\n\n        public Rect ReadRect(Rect aDefault)\n        {\n            if (IsObject)\n                return new Rect(this[\"x\"].AsFloat, this[\"y\"].AsFloat, this[\"width\"].AsFloat,\n                    this[\"height\"].AsFloat);\n            if (IsArray)\n                return new Rect(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat);\n            return aDefault;\n        }\n\n        public Rect ReadRect()\n        {\n            return ReadRect(new Rect());\n        }\n\n        public JSONNode WriteRect(Rect aRect)\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[\"x\"].AsFloat = aRect.x;\n                this[\"y\"].AsFloat = aRect.y;\n                this[\"width\"].AsFloat = aRect.width;\n                this[\"height\"].AsFloat = aRect.height;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsFloat = aRect.x;\n                this[1].AsFloat = aRect.y;\n                this[2].AsFloat = aRect.width;\n                this[3].AsFloat = aRect.height;\n            }\n\n            return this;\n        }\n\n        #endregion Rect\n\n        #region RectOffset\n\n        public RectOffset ReadRectOffset(RectOffset aDefault)\n        {\n            if (this is JSONObject)\n                return new RectOffset(this[\"left\"].AsInt, this[\"right\"].AsInt, this[\"top\"].AsInt,\n                    this[\"bottom\"].AsInt);\n            if (this is JSONArray)\n                return new RectOffset(this[0].AsInt, this[1].AsInt, this[2].AsInt, this[3].AsInt);\n            return aDefault;\n        }\n\n        public RectOffset ReadRectOffset()\n        {\n            return ReadRectOffset(new RectOffset());\n        }\n\n        public JSONNode WriteRectOffset(RectOffset aRect)\n        {\n            if (IsObject)\n            {\n                Inline = true;\n                this[\"left\"].AsInt = aRect.left;\n                this[\"right\"].AsInt = aRect.right;\n                this[\"top\"].AsInt = aRect.top;\n                this[\"bottom\"].AsInt = aRect.bottom;\n            }\n            else if (IsArray)\n            {\n                Inline = true;\n                this[0].AsInt = aRect.left;\n                this[1].AsInt = aRect.right;\n                this[2].AsInt = aRect.top;\n                this[3].AsInt = aRect.bottom;\n            }\n\n            return this;\n        }\n\n        #endregion RectOffset\n\n        #region Matrix4x4\n\n        public Matrix4x4 ReadMatrix()\n        {\n            Matrix4x4 result = Matrix4x4.identity;\n            if (IsArray)\n            {\n                for (int i = 0; i < 16; i++)\n                {\n                    result[i] = this[i].AsFloat;\n                }\n            }\n\n            return result;\n        }\n\n        public JSONNode WriteMatrix(Matrix4x4 aMatrix)\n        {\n            if (IsArray)\n            {\n                Inline = true;\n                for (int i = 0; i < 16; i++)\n                {\n                    this[i].AsFloat = aMatrix[i];\n                }\n            }\n\n            return this;\n        }\n\n        #endregion Matrix4x4\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/SimpleJSON/SimpleJSONUnity.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e6d6a5e58d63bf34f9547da8fda47814\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/SimpleJSON/Virtuesky.Sunflower.SimpleJson.asmdef",
    "content": "{\n\t\"name\": \"Virtuesky.Sunflower.SimpleJson\"\n}\n"
  },
  {
    "path": "VirtueSky/SimpleJSON/Virtuesky.Sunflower.SimpleJson.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 98c7400721ddc874d9bad4ee2f3f66d6\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/SimpleJSON.meta",
    "content": "fileFormatVersion: 2\nguid: cb55fbcbb2ac561488658e5088c404b8\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Editor/TouchInputManagerEditor.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.TouchInput\n{\n    [CustomEditor(typeof(TouchInputManager))]\n    public class TouchInputManagerEditor : Editor\n    {\n        private SerializedProperty _inputEventTouchBegin;\n        private SerializedProperty _inputEventTouchMove;\n        private SerializedProperty _inputEventTouchStationary;\n        private SerializedProperty _inputEventTouchEnd;\n        private SerializedProperty _inputEventTouchCancel;\n        private SerializedProperty _inputPreventTouchVariable;\n        private SerializedProperty _preventTouch;\n        private SerializedProperty _touchPosition;\n        private const string path = \"/InputEvent\";\n\n        void Init()\n        {\n            _inputEventTouchBegin = serializedObject.FindProperty(\"inputEventTouchBegin\");\n            _inputEventTouchMove = serializedObject.FindProperty(\"inputEventTouchMove\");\n            _inputEventTouchStationary = serializedObject.FindProperty(\"inputEventTouchStationary\");\n            _inputEventTouchEnd = serializedObject.FindProperty(\"inputEventTouchEnd\");\n            _inputEventTouchCancel = serializedObject.FindProperty(\"inputEventTouchCancel\");\n            _inputPreventTouchVariable = serializedObject.FindProperty(\"inputPreventTouchVariable\");\n            _preventTouch = serializedObject.FindProperty(\"preventTouch\");\n            _touchPosition = serializedObject.FindProperty(\"touchPosition\");\n        }\n\n        private void OnEnable()\n        {\n            Init();\n        }\n\n        public override void OnInspectorGUI()\n        {\n            serializedObject.Update();\n            DrawEvent<InputEventTouchBegin>(ref _inputEventTouchBegin, \"input_event_touch_begin\");\n            DrawEvent<InputEventTouchMove>(ref _inputEventTouchMove, \"input_event_touch_move\");\n            DrawEvent<InputEventTouchStationary>(ref _inputEventTouchStationary, \"input_event_touch_stationary\");\n            DrawEvent<InputEventTouchEnd>(ref _inputEventTouchEnd, \"input_event_touch_end\");\n            DrawEvent<InputEventTouchCancel>(ref _inputEventTouchCancel, \"input_event_touch_cancel\");\n            GUILayout.Space(5);\n            DrawEvent<InputPreventTouchVariable>(ref _inputPreventTouchVariable, \"input_prevent_touch_variable\");\n            GUILayout.Space(5);\n            if (Application.isPlaying)\n            {\n                EditorGUILayout.PropertyField(_preventTouch);\n            }\n\n            GUILayout.Space(5);\n            if (Application.isPlaying)\n            {\n                EditorGUILayout.PropertyField(_touchPosition);\n            }\n\n            EditorUtility.SetDirty(target);\n            serializedObject.ApplyModifiedProperties();\n            //serializedObject.Update();\n        }\n\n        void DrawEvent<T>(ref SerializedProperty inputEvent, string eventName)\n            where T : ScriptableObject\n        {\n            EditorGUILayout.BeginHorizontal();\n            EditorGUILayout.PropertyField(inputEvent);\n            if (inputEvent.objectReferenceValue == null)\n            {\n                GUILayout.Space(2);\n                if (GUILayout.Button(\"Create\", GUILayout.Width(55)))\n                {\n                    inputEvent.objectReferenceValue =\n                        CreateAsset.CreateAndGetScriptableAsset<T>(path, eventName, false);\n                }\n            }\n\n            EditorGUILayout.EndHorizontal();\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Editor/TouchInputManagerEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 835c66fdab2646d09a76ee5dbefb37f3\ntimeCreated: 1720080548"
  },
  {
    "path": "VirtueSky/TouchInput/Editor/Virtuesky.Sunflower.TouchInput.Editor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.TouchInput.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:fe2654b21280dcc4b8f7cff43f5cc40b\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:35d694408290717499b3838802212c7f\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Editor/Virtuesky.Sunflower.TouchInput.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 7181056f59e7ba54bba1d2c0fd95040a\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: d8cf9d9d575f4974daa4cb8dee0308b1\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchBegin.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.TouchInput\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Touch Input/Event Touch Begin\",\n        fileName = \"input_event_touch_begin\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class InputEventTouchBegin : Vector3Event\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchBegin.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ec1309b8f71347d18122f9aec5119ed8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchCancel.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.TouchInput\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Touch Input/Event Touch Cancel\",\n        fileName = \"input_event_touch_cancel\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class InputEventTouchCancel : Vector3Event\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchCancel.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d8fb1dea22af4b9a980d72ef7e9be012\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchEnd.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.TouchInput\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Touch Input/Event Touch End\",\n        fileName = \"input_event_touch_end\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class InputEventTouchEnd : Vector3Event\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchEnd.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 81b183cd299f40398bab05815b4800a7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchMove.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.TouchInput\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Touch Input/Event Touch Move\",\n        fileName = \"input_event_touch_move\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class InputEventTouchMove : Vector3Event\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchMove.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7df8998bdaa34b7da53c859d6b828ff5\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchStationary.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.TouchInput\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Touch Input/Event Touch Stationary\",\n        fileName = \"input_event_touch_stationary\")]\n    [EditorIcon(\"scriptable_event\")]\n    public class InputEventTouchStationary : Vector3Event\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputEventTouchStationary.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 448e981eafa6406484aaae4ddb2250ea\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 5ad7786ac7818964c9714ea071b638b3, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputPreventTouchVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Variables;\n\nnamespace VirtueSky.TouchInput\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Touch Input/Variable Prevent Touch\",\n        fileName = \"input_prevent_touch_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class InputPreventTouchVariable : BooleanVariable\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent/InputPreventTouchVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1c6aaa729cc54f81b082dd389895da05\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/InputTouchEvent.meta",
    "content": "fileFormatVersion: 2\nguid: fe39cac498644a3995c160b428b65e74\ntimeCreated: 1720082877"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/TouchInputManager.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.TouchInput\n{\n    [EditorIcon(\"icon_controller\")]\n    public class TouchInputManager : MonoBehaviour\n    {\n        [SerializeField, Tooltip(\"Event A finger touched the screen\")]\n        private InputEventTouchBegin inputEventTouchBegin;\n\n        [SerializeField, Tooltip(\"Event A finger moved on the screen\")]\n        private InputEventTouchMove inputEventTouchMove;\n\n        [SerializeField, Tooltip(\"Event A finger is touching the screen but hasn't moved\")]\n        private InputEventTouchStationary inputEventTouchStationary;\n\n        [SerializeField, Tooltip(\"Event A finger was lifted from the screen. This is the final phase of a touch\")]\n        private InputEventTouchEnd inputEventTouchEnd;\n\n        [SerializeField, Tooltip(\"The system cancelled tracking for the touch\")]\n        private InputEventTouchCancel inputEventTouchCancel;\n\n        [SerializeField, Tooltip(\"Prevent touch variable\")]\n        private InputPreventTouchVariable inputPreventTouchVariable;\n\n        [SerializeField] private Vector3 touchPosition;\n        [SerializeField] private bool preventTouch = false;\n        private bool _mouseDown;\n        private bool _mouseUpdate;\n\n\n        private void OnEnable()\n        {\n            if (inputPreventTouchVariable != null)\n            {\n                inputPreventTouchVariable.Value = preventTouch;\n                inputPreventTouchVariable.AddListener(OnChangePreventTouch);\n            }\n        }\n\n        private void OnDisable()\n        {\n            if (inputPreventTouchVariable != null)\n            {\n                inputPreventTouchVariable.RemoveListener(OnChangePreventTouch);\n            }\n        }\n\n        void OnChangePreventTouch(bool prevent)\n        {\n            preventTouch = prevent;\n        }\n\n        private void Update()\n        {\n            if (preventTouch) return;\n#if UNITY_EDITOR\n            if (UnityEngine.Device.SystemInfo.deviceType != DeviceType.Desktop)\n            {\n                HandleTouch();\n            }\n            else\n            {\n                HandleMouse();\n            }\n#else\n            HandleTouch();\n#endif\n        }\n\n        void HandleTouch()\n        {\n            if (Input.touchCount > 0)\n            {\n                Touch touch = Input.GetTouch(0);\n                switch (touch.phase)\n                {\n                    case TouchPhase.Began:\n                        if (inputEventTouchBegin != null)\n                        {\n                            inputEventTouchBegin.Raise(touch.position);\n                        }\n\n                        break;\n                    case TouchPhase.Moved:\n                        if (inputEventTouchMove != null)\n                        {\n                            inputEventTouchMove.Raise(touch.position);\n                        }\n\n                        break;\n                    case TouchPhase.Stationary:\n                        if (inputEventTouchStationary != null)\n                        {\n                            inputEventTouchStationary.Raise(touch.position);\n                        }\n\n                        break;\n                    case TouchPhase.Ended:\n                        if (inputEventTouchEnd != null)\n                        {\n                            inputEventTouchEnd.Raise(touch.position);\n                        }\n\n                        break;\n                    case TouchPhase.Canceled:\n                        if (inputEventTouchCancel != null)\n                        {\n                            inputEventTouchCancel.Raise(touch.position);\n                        }\n\n                        break;\n                }\n\n                touchPosition = touch.position;\n            }\n        }\n\n        void HandleMouse()\n        {\n            if (Input.GetMouseButtonDown(0))\n            {\n                if (!_mouseDown)\n                {\n                    _mouseDown = true;\n                    _mouseUpdate = true;\n                    if (inputEventTouchBegin != null)\n                    {\n                        inputEventTouchBegin.Raise(Input.mousePosition);\n                    }\n\n                    touchPosition = Input.mousePosition;\n                }\n            }\n            else if (Input.GetMouseButtonUp(0))\n            {\n                _mouseDown = false;\n                _mouseUpdate = false;\n                if (inputEventTouchEnd != null)\n                {\n                    inputEventTouchEnd.Raise(Input.mousePosition);\n                }\n\n                touchPosition = Input.mousePosition;\n            }\n\n            if (_mouseDown && _mouseUpdate)\n            {\n                if (inputEventTouchMove != null)\n                {\n                    inputEventTouchMove.Raise(Input.mousePosition);\n                }\n\n                touchPosition = Input.mousePosition;\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/TouchInputManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c749a2fdea6f4e87b4cf5c41c5da0d2c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 1c63e3b6583d6b54a8de6efcd2a86725, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/Virtuesky.Sunflower.TouchInput.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.TouchInput\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:324caed91501a9c47a04ebfd87b68794\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:35d694408290717499b3838802212c7f\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime/Virtuesky.Sunflower.TouchInput.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: fe2654b21280dcc4b8f7cff43f5cc40b\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: f1cb1395cead95140be8aa6bcc771f2d\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/TouchInput.meta",
    "content": "fileFormatVersion: 2\nguid: f16b4384183147518ca672ec7e42afb4\ntimeCreated: 1720080116"
  },
  {
    "path": "VirtueSky/Tracking/Editor/TrackingWindowEditor.cs",
    "content": "using UnityEditor;\nusing VirtueSky.Tracking;\nusing VirtueSky.UtilsEditor;\n\npublic class TrackingWindowEditor : EditorWindow\n{\n    private const string pathFirebaseTracking = \"/FirebaseAnalytic_Tracking\";\n    private const string pathAdjustTracking = \"/AdjustTracking\";\n    private const string pathAppsFlyerTracking = \"/AppsFlyerTracking\";\n\n    #region Firebase Tracking\n\n    // [MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase No Param\")]\n    public static void CreateLogEventFirebaseNoParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseNoParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_no_param\");\n    }\n\n    //  [MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase 1 Param\")]\n    public static void CreateLogEventFirebaseOneParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseOneParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_1_param\");\n    }\n\n    // [MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase 2 Param\")]\n    public static void CreateLogEventFirebaseTwoParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseTwoParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_2_param\");\n    }\n\n    //[MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase 3 Param\")]\n    public static void CreateLogEventFirebaseThreeParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseThreeParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_3_param\");\n    }\n\n    //[MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase 4 Param\")]\n    public static void CreateLogEventFirebaseFourParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseFourParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_4_param\");\n    }\n\n    // [MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase 5 Param\")]\n    public static void CreateLogEventFirebaseFiveParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseFiveParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_5_param\");\n    }\n\n    //  [MenuItem(\"Sunflower/Firebase Analytic/Log Event Firebase 6 Param\")]\n    public static void CreateLogEventFirebaseSixParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingFirebaseSixParam>(\n            pathFirebaseTracking,\n            \"tracking_firebase_6_param\");\n    }\n\n    #endregion\n\n    #region AppsFlyer Tracking\n\n    public static void CreateTrackingAfNoParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerNoParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_no_param\");\n    }\n\n    public static void CreateTrackingAf1Param()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerOneParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_1_param\");\n    }\n\n    public static void CreateTrackingAf2Param()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerTwoParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_2_param\");\n    }\n\n    public static void CreateTrackingAf3Param()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerThreeParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_3_param\");\n    }\n\n    public static void CreateTrackingAf4Param()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerFourParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_4_param\");\n    }\n\n    public static void CreateTrackingAf5Param()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerFiveParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_5_param\");\n    }\n\n    public static void CreateTrackingAfHasParam()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAppsFlyerHasParam>(pathAppsFlyerTracking,\n            \"tracking_appsflyer_has_param\");\n    }\n\n    #endregion\n\n    public static void CreateTrackingAdjust()\n    {\n        CreateAsset.CreateScriptableAssetsOnlyName<TrackingAdjust>(pathAdjustTracking, \"tracking_adjust\");\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Editor/TrackingWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 1d6eaeb455d51d14bbb078ca4ad09a96\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Editor/Virtuesky.Sunflower.TrackingEditor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.TrackingEditor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:5e9107a8f2499184ea26564811dda246\",\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Tracking/Editor/Virtuesky.Sunflower.TrackingEditor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: ade1d0a32a74d554ab9bf506427a1b1b\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: e6c252b21ccd90b4a939ad50a69e29a9\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking/AdjustConfig.cs",
    "content": "#if VIRTUESKY_ADJUST\nusing AdjustSdk;\n#endif\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Tracking\n{\n    [EditorIcon(\"icon_scriptable\"), HideMonoScript]\n    public class AdjustConfig : ScriptableSettings<AdjustConfig>\n    {\n        [SerializeField] private string appToken;\n#if VIRTUESKY_ADJUST\n        [SerializeField] private AdjustEnvironment adjustEnvironment = AdjustEnvironment.Production;\n        [SerializeField] private AdjustLogLevel logLevel = AdjustLogLevel.Error;\n#endif\n        public static string AppToken => Instance.appToken;\n#if VIRTUESKY_ADJUST\n        public static AdjustEnvironment AdjustEnvironment => Instance.adjustEnvironment;\n        public static AdjustLogLevel LogLevel => Instance.logLevel;\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking/AdjustConfig.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 34657995523d4530bc6a14476a10a838\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking/AdjustTrackingRevenue.cs",
    "content": "﻿using System;\n#if VIRTUESKY_ADJUST\nusing AdjustSdk;\n#endif\n\nnamespace VirtueSky.Tracking\n{\n    public struct AdjustTrackingRevenue\n    {\n        public static Action OnTracked;\n\n        public static void AdjustTrackRevenue(double value, string network, string unitId,\n            string placement, string currentAdMediation)\n        {\n#if VIRTUESKY_ADJUST\n            var source = \"\";\n            switch (currentAdMediation.ToLower())\n            {\n                case \"admob\":\n                    source = \"admob_sdk\";\n                    break;\n                case \"applovin\":\n                    source = \"applovin_max_sdk\";\n                    break;\n                case \"levelplay\":\n                    source = \"levelplay_ironsource_sdk\";\n                    break;\n            }\n\n            AdjustAdRevenue adjustAdRevenue = new AdjustAdRevenue(source);\n            adjustAdRevenue.SetRevenue(value, \"USD\");\n            adjustAdRevenue.AdRevenueNetwork = network;\n            adjustAdRevenue.AdRevenueUnit = unitId;\n            adjustAdRevenue.AdRevenuePlacement = placement;\n            Adjust.TrackAdRevenue(adjustAdRevenue);\n            OnTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking/AdjustTrackingRevenue.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: bebd00f793cf40c6a22d584bc0ea23dc\ntimeCreated: 1704883003"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking/TrackingAdjust.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Adjust\",\n        fileName = \"tracking_adjust\")]\n    [EditorIcon(\"scriptable_adjust2\")]\n    public class TrackingAdjust : ScriptableObject\n    {\n        [HeaderLine(\"Event Token\"), SerializeField]\n        private string eventToken;\n\n        public static Action OnTracked;\n\n        public void TrackEvent()\n        {\n#if VIRTUESKY_ADJUST\n            AdjustSdk.Adjust.TrackEvent(new AdjustSdk.AdjustEvent(eventToken));\n            OnTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking/TrackingAdjust.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 669549b6839748409353138daa666c2f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: b9157b0e91856514ba3f36deebb179cd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AdjustTracking.meta",
    "content": "fileFormatVersion: 2\nguid: e5b11169aa862d440836b218bc54a382\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppTracking.cs",
    "content": "﻿namespace VirtueSky.Tracking\n{\n    public struct AppTracking\n    {\n        private static bool enableTrackRevenue;\n\n        public static void Init(bool _enableTrackRevenue)\n        {\n            enableTrackRevenue = _enableTrackRevenue;\n        }\n\n        public static void TrackRevenue(double value, string network, string unitId, string format,\n            string currentAdMediation)\n        {\n            if (!enableTrackRevenue) return;\n            AdjustTrackingRevenue.AdjustTrackRevenue(value, network, unitId, format, currentAdMediation);\n            FirebaseAnalyticTrackingRevenue.FirebaseAnalyticTrackRevenue(value, network, unitId,\n                format, currentAdMediation);\n            AppsFlyerTrackingRevenue.AppsFlyerTrackRevenueAd(value, network, unitId, format, currentAdMediation);\n        }\n\n        public static void FirebaseAnalyticTrackATTResult(int status)\n        {\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(\"app_tracking_transparency\", \"status\", status);\n#endif\n        }\n\n        public static void StartTrackingAdjust()\n        {\n#if VIRTUESKY_ADJUST\n            var adjust = new UnityEngine.GameObject(\"Adjust\", typeof(AdjustSdk.Adjust));\n            var adjustConfig = new AdjustSdk.AdjustConfig(AdjustConfig.AppToken, AdjustConfig.AdjustEnvironment,\n                AdjustConfig.LogLevel == AdjustSdk.AdjustLogLevel.Suppress)\n            {\n                LogLevel = AdjustConfig.LogLevel,\n                IsAdServicesEnabled = true,\n                IsIdfaReadingEnabled = true\n            };\n            AdjustSdk.Adjust.InitSdk(adjustConfig);\n            UnityEngine.Debug.Log($\"Start Tracking {adjust.name}\");\n#endif\n        }\n\n        public static void StartTrackingAppsFlyer()\n        {\n#if VIRTUESKY_APPSFLYER\n            var appFlyerObject =\n                new UnityEngine.GameObject(\"AppsFlyerObject\", typeof(VirtueSky.Tracking.AppsFlyerObject));\n            UnityEngine.Debug.Log($\"Start Tracking {appFlyerObject.name}\");\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppTracking.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 100aece4cce647fcac4bb39d00a7cd4c\ntimeCreated: 1696404726"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerConfig.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Tracking\n{\n    [EditorIcon(\"icon_scriptable\"), HideMonoScript]\n    public class AppsFlyerConfig : ScriptableSettings<AppsFlyerConfig>\n    {\n        [SerializeField] private string devKey;\n        [SerializeField] private string appID;\n        [SerializeField] private string uwpAppID;\n        [SerializeField] private string macOSAppID;\n        [SerializeField] private bool getConversionData;\n        [SerializeField] private bool isDebug;\n        [SerializeField] private bool isDebugAdRevenue;\n\n\n        public static string DevKey => Instance.devKey;\n        public static string AppID => Instance.appID;\n        public static string UWPAppID => Instance.uwpAppID;\n        public static string MacOSAppID => Instance.macOSAppID;\n        public static bool IsDebug => Instance.isDebug;\n        public static bool IsDebugAdRevenue => Instance.isDebugAdRevenue;\n        public static bool GetConversionData => Instance.getConversionData;\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerConfig.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7b91837cb644418dba77c9fd3ec09ec1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: ed5ec0bb4ec55df47af0ecc2bd7be5f9, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerObject.cs",
    "content": "#if VIRTUESKY_APPSFLYER\nusing AppsFlyerSDK;\n#endif\n\nusing System;\nusing UnityEngine;\n\nnamespace VirtueSky.Tracking\n{\n    public class AppsFlyerObject : MonoBehaviour\n    {\n        private void Awake()\n        {\n#if !UNITY_EDITOR\n            DontDestroyOnLoad(this);\n#endif\n        }\n\n        private void Start()\n        {\n#if VIRTUESKY_APPSFLYER\n            // These fields are set from the editor so do not modify!\n            //******************************//\n            AppsFlyer.setIsDebug(AppsFlyerConfig.IsDebug);\n#if UNITY_WSA_10_0 && !UNITY_EDITOR\n            AppsFlyer.initSDK(AppsFlyerSetting.DevKey, AppsFlyerSetting.UWPAppID,\n                AppsFlyerSetting.GetConversionData ? this : null);\n#elif UNITY_STANDALONE_OSX && !UNITY_EDITOR\n            AppsFlyer.initSDK(AppsFlyerSetting.DevKey, AppsFlyerSetting.MacOSAppID,\n                AppsFlyerSetting.GetConversionData ? this : null);\n#else\n\n            AppsFlyer.initSDK(AppsFlyerConfig.DevKey, AppsFlyerConfig.AppID,\n                AppsFlyerConfig.GetConversionData ? this : null);\n#endif\n            //******************************/\n\n            AppsFlyer.startSDK();\n\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerObject.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a110a1c48939450aa0b0517c5ccd7f1b\ntimeCreated: 1723541286"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerTrackingRevenue.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n#if VIRTUESKY_APPSFLYER\nusing AppsFlyerSDK;\n#endif\n\n#if VIRTUESKY_IAP\nusing UnityEngine.Purchasing;\n#endif\n\n\nnamespace VirtueSky.Tracking\n{\n    public struct AppsFlyerTrackingRevenue\n    {\n        public static Action OnTracked;\n        public static void AppsFlyerTrackRevenueAd(double value, string network, string unitId,\n            string format, string currentAdMediation)\n        {\n#if VIRTUESKY_APPSFLYER\n            var mediationNetworks = MediationNetwork.GoogleAdMob;\n            switch (currentAdMediation.ToLower())\n            {\n                case \"admob\":\n                    mediationNetworks = MediationNetwork.GoogleAdMob;\n                    break;\n                case \"applovin\":\n                    mediationNetworks = MediationNetwork.ApplovinMax;\n                    break;\n                case \"levelplay\":\n                    mediationNetworks = MediationNetwork.IronSource;\n                    break;\n            }\n\n            Dictionary<string, string> additionalParams = new Dictionary<string, string>();\n            additionalParams.Add(AdRevenueScheme.COUNTRY, \"US\");\n            additionalParams.Add(AdRevenueScheme.AD_UNIT, unitId);\n            additionalParams.Add(AdRevenueScheme.AD_TYPE, format);\n            AppsFlyer.logAdRevenue(new AFAdRevenueData(network, mediationNetworks, \"USD\", value), additionalParams);\n            OnTracked?.Invoke();\n#endif\n        }\n#if VIRTUESKY_APPSFLYER && VIRTUESKY_IAP\n        public static void AppFlyerTrackingRevenueInAppPurchase(Product product)\n        {\n            Dictionary<string, string> eventValue = new Dictionary<string, string>();\n            eventValue.Add(\"af_revenue\", GetAppsflyerRevenue(product.metadata.localizedPrice));\n            eventValue.Add(\"af_content_id\", product.definition.id);\n            eventValue.Add(\"af_currency\", product.metadata.isoCurrencyCode);\n            AppsFlyer.sendEvent(\"af_purchase\", eventValue);\n        }\n\n        public static string GetAppsflyerRevenue(decimal amount)\n        {\n            decimal val = decimal.Multiply(amount, 0.63m);\n            return val.ToString();\n        }\n\n#endif\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/AppsFlyerTrackingRevenue.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4e397132c1af4396bc9609457c04e02a\ntimeCreated: 1704883287"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyer.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    public abstract class TrackingAppsFlyer : ScriptableObject\n    {\n        [Space, HeaderLine(\"Event Name\"), SerializeField]\n        protected string eventName;\n\n        protected Action onTracked;\n\n        public event Action OnTracked\n        {\n            add => onTracked += value;\n            remove => onTracked -= value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyer.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9598a59ad0b34a31a20817d3aa99c4f0\ntimeCreated: 1728964263"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFiveParam.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking 5 Param\",\n        fileName = \"tracking_appsflyer_5_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerFiveParam : TrackingAppsFlyer\n    {\n        [Space, HeaderLine(\"Parameter Name\"), SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n        [SerializeField] private string parameterName4;\n        [SerializeField] private string parameterName5;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3,\n            string parameterValue4, string parameterValue5)\n        {\n#if VIRTUESKY_APPSFLYER\n            Dictionary<string, string> eventValues = new Dictionary<string, string>();\n            eventValues.Add(parameterName1, parameterValue1);\n            eventValues.Add(parameterName2, parameterValue2);\n            eventValues.Add(parameterName3, parameterValue3);\n            eventValues.Add(parameterName4, parameterValue4);\n            eventValues.Add(parameterName5, parameterValue5);\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFiveParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0706da9436ff406ba4cba1c0ce0f8a34\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFourParam.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking 4 Param\",\n        fileName = \"tracking_appsflyer_4_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerFourParam : TrackingAppsFlyer\n    {\n        [Space, HeaderLine(\"Parameter Name\"), SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n        [SerializeField] private string parameterName4;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3,\n            string parameterValue4)\n        {\n#if VIRTUESKY_APPSFLYER\n            Dictionary<string, string> eventValues = new Dictionary<string, string>();\n            eventValues.Add(parameterName1, parameterValue1);\n            eventValues.Add(parameterName2, parameterValue2);\n            eventValues.Add(parameterName3, parameterValue3);\n            eventValues.Add(parameterName4, parameterValue4);\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerFourParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4b2796bc39ac4335890159d6a5758a51\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerHasParam.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\nusing VirtueSky.Misc;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking Has Param\",\n        fileName = \"tracking_appsflyer_has_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerHasParam : TrackingAppsFlyer\n    {\n        public void TrackEvent(Dictionary<string, string> eventValues)\n        {\n#if VIRTUESKY_APPSFLYER\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues);\n#endif\n        }\n\n        public void TrackEvent(List<string> paramNames, List<string> paramValues)\n        {\n#if VIRTUESKY_APPSFLYER\n            IDictionary<string, string> eventValues = paramNames.MakeDictionary(paramValues);\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, (Dictionary<string, string>)eventValues);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerHasParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 669a290e920a4cf3878a06a85ba37fa0\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerNoParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking No Param\",\n        fileName = \"tracking_appsflyer_no_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerNoParam : TrackingAppsFlyer\n    {\n        public void TrackEvent()\n        {\n#if VIRTUESKY_APPSFLYER\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, null);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerNoParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a113e27321fd46b59e8d12c1707ffe10\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerOneParam.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking 1 Param\",\n        fileName = \"tracking_appsflyer_1_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerOneParam : TrackingAppsFlyer\n    {\n        [Space, HeaderLine(\"Parameter Name\"), SerializeField]\n        private string parameterName;\n\n        public void TrackEvent(string parameterValue)\n        {\n#if VIRTUESKY_APPSFLYER\n            Dictionary<string, string> eventValues = new Dictionary<string, string>();\n            eventValues.Add(parameterName, parameterValue);\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerOneParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4d8f7c3b324d4297bf68a2072f9c4f90\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerThreeParam.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking 3 Param\",\n        fileName = \"tracking_appsflyer_3_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerThreeParam : TrackingAppsFlyer\n    {\n        [Space, HeaderLine(\"Parameter Name\"), SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3)\n        {\n#if VIRTUESKY_APPSFLYER\n            Dictionary<string, string> eventValues = new Dictionary<string, string>();\n            eventValues.Add(parameterName1, parameterValue1);\n            eventValues.Add(parameterName2, parameterValue2);\n            eventValues.Add(parameterName3, parameterValue3);\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerThreeParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f011e56fe795441db526d34550e913ef\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerTwoParam.cs",
    "content": "using System.Collections.Generic;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/AppsFlyer/Tracking 2 Param\",\n        fileName = \"tracking_appsflyer_2_param\")]\n    [EditorIcon(\"scriptable_af\")]\n    public class TrackingAppsFlyerTwoParam : TrackingAppsFlyer\n    {\n        [Space, HeaderLine(\"Parameter Name\"), SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2)\n        {\n#if VIRTUESKY_APPSFLYER\n            Dictionary<string, string> eventValues = new Dictionary<string, string>();\n            eventValues.Add(parameterName1, parameterValue1);\n            eventValues.Add(parameterName2, parameterValue2);\n            AppsFlyerSDK.AppsFlyer.sendEvent(eventName, eventValues);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking/TrackingAppsFlyerTwoParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 214872ae9c29427280cb8d1536053c22\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 923d17c486919a945a5fef5ca1ee8e9b, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/AppsFlyerTracking.meta",
    "content": "fileFormatVersion: 2\nguid: a8a61d961531cba4fb2a06c2fe643354\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/FirebaseAnalyticTrackingRevenue.cs",
    "content": "﻿using System;\n#if VIRTUESKY_FIREBASE_ANALYTIC\nusing Firebase.Analytics;\n#endif\n\nnamespace VirtueSky.Tracking\n{\n    public struct FirebaseAnalyticTrackingRevenue\n    {\n        public static Action OnTracked;\n        public static bool autoTrackAdImpressionAdmob;\n\n        public static void FirebaseAnalyticTrackRevenue(double value, string network, string unitId,\n            string format, string currentAdMediation)\n        {\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            string ad_platform = \"\";\n            switch (currentAdMediation.ToLower())\n            {\n                case \"admob\":\n                    if (autoTrackAdImpressionAdmob) return;\n                    ad_platform = \"Admob\";\n                    break;\n\n                case \"applovin\":\n                    ad_platform = \"AppLovin\";\n                    break;\n                case \"levelplay\":\n                    ad_platform = \"IronSource\";\n                    break;\n            }\n\n            Parameter[] parameters =\n            {\n                new(\"value\", value),\n                new(\"ad_platform\", ad_platform),\n                new(\"ad_format\", format),\n                new(\"currency\", \"USD\"),\n                new(\"ad_unit_id\", unitId),\n                new(\"ad_source\", network)\n            };\n\n            FirebaseAnalytics.LogEvent(\"ad_impression\", parameters);\n            OnTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/FirebaseAnalyticTrackingRevenue.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 0e69053dd6f04bdb836b272966506c95\ntimeCreated: 1704882713"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebase.cs",
    "content": "using System;\nusing UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    public abstract class TrackingFirebase : ScriptableObject\n    {\n        [Space] [HeaderLine(\"Event Name\")] [SerializeField]\n        protected string eventName;\n\n        protected Action onTracked;\n\n        public event Action OnTracked\n        {\n            add => onTracked += value;\n            remove => onTracked -= value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebase.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 02a2b0817bed4feabe60b33ab8bf18fd\ntimeCreated: 1728963039"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFiveParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking 5 Param\",\n        fileName = \"tracking_firebase_5_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseFiveParam : TrackingFirebase\n    {\n        [Space] [HeaderLine(\"Parameter Name\")] [SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n        [SerializeField] private string parameterName4;\n        [SerializeField] private string parameterName5;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3,\n            string parameterValue4, string parameterValue5)\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.Parameter[] parameters =\n            {\n                new(parameterName1, parameterValue1), new(parameterName2, parameterValue2),\n                new(parameterName3, parameterValue3), new(parameterName4, parameterValue4),\n                new(parameterName5, parameterValue5)\n            };\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFiveParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f6c32ba92556429096a143e9146cb9fe\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFourParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking 4 Param\",\n        fileName = \"tracking_firebase_4_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseFourParam : TrackingFirebase\n    {\n        [Space] [HeaderLine(\"Parameter Name\")] [SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n        [SerializeField] private string parameterName4;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3,\n            string parameterValue4)\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.Parameter[] parameters =\n            {\n                new(parameterName1, parameterValue1), new(parameterName2, parameterValue2),\n                new(parameterName3, parameterValue3), new(parameterName4, parameterValue4)\n            };\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseFourParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d3118516a2474dfbafd5f776dfdd3312\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseNoParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking No Param\",\n        fileName = \"tracking_firebase_no_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseNoParam : TrackingFirebase\n    {\n        public void TrackEvent()\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseNoParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f7a9cb05e507c704597bcb479279eb59\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseOneParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking 1 Param\",\n        fileName = \"tracking_firebase_1_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseOneParam : TrackingFirebase\n    {\n        [Space] [HeaderLine(\"Parameter Name\")] [SerializeField]\n        private string parameterName;\n\n        public void TrackEvent(string parameterValue)\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameterName, parameterValue);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseOneParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e8b5edc0caef4a02a234b4d36a5a1c2a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseSixParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking 6 Param\",\n        fileName = \"tracking_firebase_6_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseSixParam : TrackingFirebase\n    {\n        [Space] [HeaderLine(\"Parameter Name\")] [SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n        [SerializeField] private string parameterName4;\n        [SerializeField] private string parameterName5;\n        [SerializeField] private string parameterName6;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3,\n            string parameterValue4, string parameterValue5, string parameterValue6)\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.Parameter[] parameters =\n            {\n                new(parameterName1, parameterValue1), new(parameterName2, parameterValue2),\n                new(parameterName3, parameterValue3), new(parameterName4, parameterValue4),\n                new(parameterName5, parameterValue5), new(parameterName6, parameterValue6)\n            };\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseSixParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d9ec77fca5e440daad87cb6d75e5cbbc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseThreeParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking 3 Param\",\n        fileName = \"tracking_firebase_3_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseThreeParam : TrackingFirebase\n    {\n        [Space] [HeaderLine(\"Parameter Name\")] [SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n        [SerializeField] private string parameterName3;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2, string parameterValue3)\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.Parameter[] parameters =\n            {\n                new(parameterName1, parameterValue1), new(parameterName2, parameterValue2),\n                new(parameterName3, parameterValue3)\n            };\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseThreeParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 65f9fd1025e84ca58cd02e67f20b989c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseTwoParam.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Tracking\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Tracking Event/Firebase Analytic/Tracking 2 Param\",\n        fileName = \"tracking_firebase_2_param\")]\n    [EditorIcon(\"scriptable_firebase\")]\n    public class TrackingFirebaseTwoParam : TrackingFirebase\n    {\n        [Space] [HeaderLine(\"Parameter Name\")] [SerializeField]\n        private string parameterName1;\n\n        [SerializeField] private string parameterName2;\n\n        public void TrackEvent(string parameterValue1, string parameterValue2)\n        {\n            if (!Application.isMobilePlatform) return;\n#if VIRTUESKY_FIREBASE_ANALYTIC\n            Firebase.Analytics.Parameter[] parameters =\n                { new(parameterName1, parameterValue1), new(parameterName2, parameterValue2) };\n            Firebase.Analytics.FirebaseAnalytics.LogEvent(eventName, parameters);\n            onTracked?.Invoke();\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking/TrackingFirebaseTwoParam.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d48f930dfff944e4a740819da6d4a9da\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: c1bc3702a7695674fbddba3cae1c2a78, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/FirebaseAnalyticTracking.meta",
    "content": "fileFormatVersion: 2\nguid: 955e298e200b89b438b7adb5defe0e95\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/Virtuesky.Sunflower.Tracking.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Tracking\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"VirtueSky.Sunflower.Inspector\",\n        \"AppsFlyer\",\n        \"Virtuesky.Sunflower.Misc\",\n        \"Virtuesky.Sunflower.Utils\",\n        \"AdjustSdk.Scripts\",\n        \"Unity.Purchasing\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Tracking/Runtime/Virtuesky.Sunflower.Tracking.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 5e9107a8f2499184ea26564811dda246\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: e17d26aa88d483a47b93fb2a35b75a91\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Tracking.meta",
    "content": "fileFormatVersion: 2\nguid: 4e44f6988aead354092ac83733426b60\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/ConstantDefineSymbols.cs",
    "content": "namespace VirtueSky.UtilsEditor\n{\n    public class ConstantDefineSymbols\n    {\n        public const string VIRTUESKY_ADS = \"VIRTUESKY_ADS\";\n        public const string VIRTUESKY_APPLOVIN = \"VIRTUESKY_APPLOVIN\";\n        public const string VIRTUESKY_ADMOB = \"VIRTUESKY_ADMOB\";\n        public const string VIRTUESKY_LEVELPLAY = \"VIRTUESKY_LEVELPLAY\";\n        public const string VIRTUESKY_ADJUST = \"VIRTUESKY_ADJUST\";\n        public const string VIRTUESKY_FIREBASE_ANALYTIC = \"VIRTUESKY_FIREBASE_ANALYTIC\";\n        public const string VIRTUESKY_FIREBASE_REMOTECONFIG = \"VIRTUESKY_FIREBASE_REMOTECONFIG\";\n        public const string VIRTUESKY_FIREBASE = \"VIRTUESKY_FIREBASE\";\n        public const string VIRTUESKY_IAP = \"VIRTUESKY_IAP\";\n        public const string VIRTUESKY_RATING = \"VIRTUESKY_RATING\";\n        public const string VIRTUESKY_NOTIFICATION = \"VIRTUESKY_NOTIFICATION\";\n        public const string VIRTUESKY_APPSFLYER = \"VIRTUESKY_APPSFLYER\";\n        public const string PRIME_TWEEN_DOTWEEN_ADAPTER = \"PRIME_TWEEN_DOTWEEN_ADAPTER\";\n        public const string PRIME_TWEEN_SAFETY_CHECKS = \"PRIME_TWEEN_SAFETY_CHECKS\";\n        public const string VIRTUESKY_GPGS = \"VIRTUESKY_GPGS\";\n        public const string VIRTUESKY_APPLE_AUTH = \"VIRTUESKY_APPLE_AUTH\";\n        public const string VIRTUESKY_SKELETON = \"VIRTUESKY_SKELETON\";\n        public const string VIRTUESKY_ANIMANCER = \"VIRTUESKY_ANIMANCER\";\n        public const string UNITASK_ADDRESSABLE_SUPPORT = \"UNITASK_ADDRESSABLE_SUPPORT\";\n        public const string UNITASK_DOTWEEN_SUPPORT = \"UNITASK_DOTWEEN_SUPPORT\";\n        public const string UNITASK_TEXTMESHPRO_SUPPORT = \"UNITASK_TEXTMESHPRO_SUPPORT\";\n        public const string VIRTUESKY_BAKINGSHEET = \"VIRTUESKY_BAKINGSHEET\";\n        public const string VIRTUESKY_UNITY_SERVICES = \"VIRTUESKY_UNITY_SERVICES\";\n        public const string ASSET_FINDER_ADDRESSABLE = \"AssetFinderADDRESSABLE\";\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/ConstantDefineSymbols.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6dcba35e0a7aa644c932401834c3a8ed\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/CreateAsset.cs",
    "content": "using System.IO;\nusing VirtueSky.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.UtilsEditor\n{\n    public static class CreateAsset\n    {\n#if UNITY_EDITOR\n        public static T CreateScriptableAssets<T>(string path = \"\", bool isPingAsset = true, bool useDefaultPath = true)\n            where T : ScriptableObject\n        {\n            var setting = UnityEngine.ScriptableObject.CreateInstance<T>();\n            UnityEditor.AssetDatabase.CreateAsset(setting,\n                $\"{DefaultPath(path, useDefaultPath)}/{typeof(T).Name}.asset\");\n            UnityEditor.AssetDatabase.SaveAssets();\n            UnityEditor.AssetDatabase.Refresh();\n            Selection.activeObject = setting;\n            if (isPingAsset)\n            {\n                EditorGUIUtility.PingObject(setting);\n            }\n\n            Debug.Log(\n                $\"<color=Green>{typeof(T).Name} was created ad {DefaultPath(path, useDefaultPath)}/{typeof(T).Name}.asset</color>\");\n            return setting;\n        }\n\n        public static T CreateScriptableAssets<T>(string path = \"\", string name = \"\", bool isPingAsset = true,\n            bool useDefaultPath = true)\n            where T : ScriptableObject\n        {\n            string newName = name == \"\" ? typeof(T).Name : name;\n            var setting = UnityEngine.ScriptableObject.CreateInstance<T>();\n            UnityEditor.AssetDatabase.CreateAsset(setting, $\"{DefaultPath(path, useDefaultPath)}/{newName}.asset\");\n            UnityEditor.AssetDatabase.SaveAssets();\n            UnityEditor.AssetDatabase.Refresh();\n            Selection.activeObject = setting;\n            if (isPingAsset)\n            {\n                EditorGUIUtility.PingObject(setting);\n            }\n\n            Debug.Log(\n                $\"<color=Green>{newName} was created ad {DefaultPath(path, useDefaultPath)}/{newName}.asset</color>\");\n            return setting;\n        }\n\n        public static T CreateScriptableAssetsOnlyName<T>(string path = \"\", string name = \"\",\n            bool isPingAsset = true, bool useDefaultPath = true)\n            where T : ScriptableObject\n        {\n            int assetCounter = 0;\n            string assetName = name == \"\" ? $\"{typeof(T).Name}\" : name;\n            string assetPath = $\"{DefaultPath(path, useDefaultPath)}/{assetName}.asset\";\n\n            while (AssetDatabase.LoadAssetAtPath<T>(assetPath) != null)\n            {\n                assetCounter++;\n                assetPath =\n                    $\"{DefaultPath(path)}/{CreateNameBasedOnGameObjectNamingScheme(assetName, assetCounter)}.asset\";\n            }\n\n            var setting = ScriptableObject.CreateInstance<T>();\n\n            UnityEditor.AssetDatabase.CreateAsset(setting, assetPath);\n            UnityEditor.AssetDatabase.SaveAssets();\n            UnityEditor.AssetDatabase.Refresh();\n            Selection.activeObject = setting;\n            if (isPingAsset)\n            {\n                EditorGUIUtility.PingObject(setting);\n            }\n\n            Debug.Log(\n                $\"<color=Green>{typeof(T).Name} was created at {assetPath}</color>\");\n            return setting;\n        }\n\n\n        public static T CreateAndGetScriptableAsset<T>(string path = \"\", string assetName = \"\", bool isPingAsset = true, bool useDefaultPath = true) where T : ScriptableObject\n        {\n            var so = GetScriptableAsset<T>();\n            if (so == null)\n            {\n                CreateScriptableAssets<T>(path, assetName, isPingAsset, useDefaultPath);\n                so = GetScriptableAsset<T>();\n            }\n\n            return so;\n        }\n\n        public static T CreateAndGetScriptableAssetByName<T>(string path = \"\", string assetName = \"\", bool isPingAsset = true, bool useDefaultPath = true)\n            where T : ScriptableObject\n        {\n            var so = GetScriptableAssetByName<T>(assetName);\n            if (so == null)\n            {\n                CreateScriptableAssets<T>(path, assetName, isPingAsset, useDefaultPath);\n                so = GetScriptableAssetByName<T>(assetName);\n            }\n\n            return so;\n        }\n\n        public static T GetScriptableAsset<T>() where T : ScriptableObject\n        {\n            return FileExtension.FindAssetAtFolder<T>(new string[] { \"Assets\" }).FirstOrDefault();\n        }\n\n        public static T GetScriptableAssetByName<T>(string name) where T : ScriptableObject\n        {\n            var arr = FileExtension.FindAssetAtFolder<T>(new string[] { \"Assets\" });\n            foreach (var asset in arr)\n            {\n                if (asset.name == name) return asset;\n            }\n\n            return null;\n        }\n\n        // public enum NamingScheme\n        // {\n        //     /// <summary>\n        //     ///   <para>Adds a space and a number in parenthesis to the name of an instantiated or duplicated GameObject (\"Prefab (1)\").</para>\n        //     /// </summary>\n        //     SpaceParenthesis,\n        //     /// <summary>\n        //     ///   <para>Adds a dot followed by a number to the name of an instantiated or duplicated GameObject (\"Prefab.1\").</para>\n        //     /// </summary>\n        //     Dot,\n        //     /// <summary>\n        //     ///   <para>Adds an underscore and a number to the name of an instantiated or duplicated GameObject (\"Prefab_1\").</para>\n        //     /// </summary>\n        //     Underscore,\n        // }\n        private static string CreateNameBasedOnGameObjectNamingScheme(string baseName, int counter)\n        {\n            EditorSettings.NamingScheme currentNamingScheme = EditorSettings.gameObjectNamingScheme;\n            return currentNamingScheme switch\n            {\n                EditorSettings.NamingScheme.SpaceParenthesis => $\"{baseName} ({counter})\",\n                EditorSettings.NamingScheme.Dot => $\"{baseName}.{counter}\",\n                EditorSettings.NamingScheme.Underscore => $\"{baseName}_{counter}\",\n                _ => $\"{baseName} ({counter})\"\n            };\n        }\n#endif\n\n\n        public static string DefaultPath(string path = \"\", bool useDefaultPath = true)\n        {\n            if (useDefaultPath)\n            {\n                const string defaultPath = \"Assets/_Sunflower/Scriptable\";\n                ValidatePath(defaultPath + path);\n                return defaultPath + path;\n            }\n\n            ValidatePath(path);\n            return path;\n        }\n\n        public static void ValidatePath(string path)\n        {\n            if (!Directory.Exists(path))\n            {\n                Directory.CreateDirectory(path);\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/CreateAsset.cs.meta",
    "content": "fileFormatVersion: 2\nguid: cdadc765aa5c5be4b9bb188ba0701a4c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorCoroutine.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.UtilsEditor\n{\n    /// <summary>\n    /// Represents a coroutine that has been started running in the editor.\n    /// <para>\n    /// Also offers static methods for <see cref=\"Start\">starting</see> and <see cref=\"Stop()\">stopping</see> coroutines.\n    /// </para>\n    /// </summary>\n    public sealed class EditorCoroutine : YieldInstruction\n    {\n        public static event Action<EditorCoroutine> Stopped;\n        private static readonly List<EditorCoroutine> Running = new(1);\n        private static readonly FieldInfo WaitForSecondsSecondsField;\n        private static readonly MethodInfo InvokeCompletionEventMethod;\n\n        private readonly Stack<object> _yielding = new(1);\n        private double _waitUntil;\n\n        public bool IsFinished => _yielding.Count == 0;\n\n        static EditorCoroutine()\n        {\n            WaitForSecondsSecondsField = typeof(WaitForSeconds).GetField(\"m_Seconds\",\n                BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n            if (WaitForSecondsSecondsField is null) Debug.LogWarning(\"Field WaitForSeconds.m_Seconds not found.\");\n            InvokeCompletionEventMethod = typeof(AsyncOperation).GetMethod(\"InvokeCompletionEvent\",\n                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);\n            if (InvokeCompletionEventMethod is null)\n                Debug.LogWarning(\"Method AsyncOperation.InvokeCompletionEvent not found.\");\n        }\n\n        private EditorCoroutine(IEnumerator routine) => _yielding.Push(routine);\n\n        /// <summary>\n        /// Starts the provided <paramref name=\"coroutine\"/>.\n        /// </summary>\n        /// <param name=\"coroutine\"> The coroutine to start. </param>\n        /// <returns>\n        /// A reference to the started <paramref name=\"coroutine\"/>.\n        /// <para>\n        /// This reference can be passed to <see cref=\"Stop()\"/> to stop\n        /// the execution of the coroutine.\n        /// </para>\n        /// </returns>\n        public static EditorCoroutine Start(IEnumerator coroutine)\n        {\n            if (Running.Count == 0) EditorApplication.update += UpdateRunningCoroutines;\n\n            var editorCoroutine = new EditorCoroutine(coroutine);\n            Running.Add(editorCoroutine);\n            return editorCoroutine;\n        }\n\n        /// <summary>\n        /// Stops the coroutine that is running in edit mode.\n        /// </summary>\n        public void Stop()\n        {\n            Running.Remove(this);\n\n            if (Running.Count == 0) EditorApplication.update -= UpdateRunningCoroutines;\n\n            Stopped?.Invoke(this);\n        }\n\n        /// <summary>\n        /// Stops the <paramref name=\"coroutine\"/> that is running.\n        /// </summary>\n        /// <param name=\"coroutine\"> The <see cref=\"IEnumerator\">coroutine</see> to stop. </param>\n        public static void Stop(IEnumerator coroutine)\n        {\n            foreach (var editorCoroutine in Running)\n            {\n                int counter = editorCoroutine._yielding.Count;\n\n                foreach (object item in editorCoroutine._yielding)\n                {\n                    if (counter == 1 && item == coroutine)\n                    {\n                        editorCoroutine.Stop();\n                        return;\n                    }\n\n                    counter--;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Stops all coroutines that have been started using <see cref=\"Start\"/> that are currently still running.\n        /// </summary>\n        public static void StopAll()\n        {\n            Running.Clear();\n            EditorApplication.update -= UpdateRunningCoroutines;\n        }\n\n        /// <summary>\n        /// Continuously advances all currently running coroutines to their\n        /// next phases until all of them have reached the end.\n        /// <para>\n        /// Note that this locks the current thread until all running coroutines have fully finished.\n        /// If any coroutine contains <see cref=\"CustomYieldInstruction\">CustomYieldInstructions</see>\n        /// that take a long time to finish (or never finish in edit mode) this can cause the editor\n        /// to freeze for the same duration.\n        /// </para>\n        /// </summary>\n        public static void MoveAllToEnd()\n        {\n            int count = Running.Count;\n            while (count > 0)\n            {\n                for (int i = count - 1; i >= 0; i--)\n                {\n                    Running[i].MoveNext(true);\n                }\n\n                count = Running.Count;\n            }\n        }\n\n        /// <summary>\n        /// Advances all currently running coroutine to their next phase.\n        /// </summary>\n        /// <param name=\"skipWaits\">\n        /// (Optional) If <see langword=\"true\"/> then yield instructions\n        /// <see cref=\"WaitForSeconds\"/> and <see cref=\"WaitForSecondsRealtime\"/> are skipped.\n        /// </param>\n        /// <returns> <see langword=\"true\"/> if any coroutines are still running, <see langword=\"false\"/> if all have finished. </returns>\n        public static bool MoveAllNext(bool skipWaits = false)\n        {\n            for (int i = Running.Count - 1; i >= 0; i--)\n            {\n                Running[i].MoveNext(skipWaits);\n            }\n\n            return Running.Count > 0;\n        }\n\n        private static void UpdateRunningCoroutines()\n        {\n            for (int i = Running.Count - 1; i >= 0; i--)\n            {\n                Running[i].MoveNext();\n            }\n        }\n\n        /// <summary>\n        /// Advances the coroutine to the next phase.\n        /// </summary>\n        /// <param name=\"skipWaits\">\n        /// (Optional) If <see langword=\"true\"/> then yield instructions\n        /// <see cref=\"WaitForSeconds\"/> and <see cref=\"WaitForSecondsRealtime\"/> are skipped.\n        /// </param>\n        /// <returns> <see langword=\"true\"/> if coroutine is still running, <see langword=\"false\"/> if it has finished. </returns>\n        public bool MoveNext(bool skipWaits = false)\n        {\n            if (EditorApplication.timeSinceStartup < _waitUntil && !skipWaits) return true;\n\n            if (_yielding.Count == 0)\n            {\n                Stop();\n                return false;\n            }\n\n            object current = _yielding.Peek();\n\n            if (current is IEnumerator enumerator)\n            {\n                bool keepWaiting;\n                try\n                {\n                    keepWaiting = enumerator.MoveNext();\n                }\n                catch\n                {\n                    keepWaiting = true;\n                }\n\n                if (!keepWaiting)\n                {\n                    _yielding.Pop();\n                    if (_yielding.Count > 0) return true;\n\n                    Stop();\n                    return false;\n                }\n\n                _yielding.Push(enumerator.Current);\n                return true;\n            }\n\n            else if (current is CustomYieldInstruction yieldInstruction)\n            {\n                bool keepWaiting;\n                try\n                {\n                    keepWaiting = yieldInstruction.keepWaiting;\n                }\n                catch\n                {\n                    keepWaiting = true;\n                }\n\n                if (!skipWaits)\n                {\n                    if (!keepWaiting) _yielding.Pop();\n\n                    return true;\n                }\n            }\n\n            else if (current is WaitForSeconds waitForSeconds)\n            {\n                _waitUntil = EditorApplication.timeSinceStartup +\n                             (float)WaitForSecondsSecondsField.GetValue(waitForSeconds);\n                if (!skipWaits)\n                {\n                    _yielding.Pop();\n                    return true;\n                }\n            }\n\n            else if (current is WaitForSecondsRealtime waitForSecondsRealtime)\n            {\n                _waitUntil = EditorApplication.timeSinceStartup + waitForSecondsRealtime.waitTime;\n                if (!skipWaits)\n                {\n                    _yielding.Pop();\n                    return true;\n                }\n            }\n\n            else if (current is WaitForEndOfFrame or WaitForFixedUpdate)\n            {\n                if (!skipWaits)\n                {\n                    _yielding.Pop();\n                    return true;\n                }\n            }\n\n            else if (current is AsyncOperation { isDone: false } asyncOperation)\n            {\n                if (!skipWaits) return true;\n\n                InvokeCompletionEventMethod?.Invoke(asyncOperation, null);\n            }\n\n            _yielding.Pop();\n            if (_yielding.Count > 0)\n            {\n                return true;\n            }\n\n            Stop();\n            return false;\n        }\n\n        /// <summary>\n        /// Continuously advances the coroutine to the next phase until it has reached the end.\n        /// <para>\n        /// Note that this locks the current thread until the coroutine has fully finished.\n        /// If the coroutine contains <see cref=\"CustomYieldInstruction\">CustomYieldInstructions</see>\n        /// that take a long time to finish (or never finish in edit mode) this can cause the editor\n        /// to freeze for the same duration.\n        /// </para>\n        /// </summary>\n        public void MoveToEnd()\n        {\n            while (MoveNext(true))\n            {\n            }\n        }\n\n        public bool Equals(IEnumerator coroutine)\n        {\n            int counter = _yielding.Count;\n            foreach (object item in _yielding)\n            {\n                if (counter == 1 && item == coroutine) return true;\n\n                counter--;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorCoroutine.cs.meta",
    "content": "fileFormatVersion: 2\nguid: fa886bf37579454bb7ef3eb488fc6d58\ntimeCreated: 1729182951"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorGUIUtils.cs",
    "content": "using UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.UtilsEditor\n{\n#if UNITY_EDITOR\n    public static class EditorGUIUtils\n    {\n        public class DisabledGUI : System.IDisposable\n        {\n            bool enabled;\n\n            public DisabledGUI(bool disable)\n            {\n                enabled = GUI.enabled;\n                GUI.enabled = !disable;\n            }\n\n            public void Dispose()\n            {\n                GUI.enabled = enabled;\n            }\n        }\n\n        public class GUIColor : System.IDisposable\n        {\n            Color c;\n\n            public GUIColor(Color c)\n            {\n                this.c = GUI.color;\n                GUI.color = c;\n            }\n\n            public void Dispose()\n            {\n                GUI.color = c;\n            }\n        }\n\n        public class BackgroundColor : System.IDisposable\n        {\n            Color c;\n\n            public BackgroundColor(Color c)\n            {\n                this.c = GUI.color;\n                GUI.backgroundColor = c;\n            }\n\n            public void Dispose()\n            {\n                GUI.backgroundColor = c;\n            }\n        }\n\n        public class GizmosColor : System.IDisposable\n        {\n            Color c;\n\n            public GizmosColor(Color c)\n            {\n                this.c = Gizmos.color;\n                Gizmos.color = c;\n            }\n\n            public void Dispose()\n            {\n                Gizmos.color = c;\n            }\n        }\n\n        public class HandlesColor : System.IDisposable\n        {\n            Color c;\n\n            public HandlesColor(Color c)\n            {\n                this.c = Handles.color;\n                Handles.color = c;\n            }\n\n            public void Dispose()\n            {\n                Handles.color = c;\n            }\n        }\n\n        public class VerticalHelpBox : System.IDisposable\n        {\n            public VerticalHelpBox(params GUILayoutOption[] options)\n            {\n                EditorGUILayout.BeginVertical(EditorStyles.helpBox, options);\n            }\n\n            public void Dispose()\n            {\n                EditorGUILayout.EndVertical();\n            }\n        }\n\n        public class HorizontalHelpBox : System.IDisposable\n        {\n            public HorizontalHelpBox(params GUILayoutOption[] options)\n            {\n                EditorGUILayout.BeginHorizontal(EditorStyles.helpBox, options);\n            }\n\n            public void Dispose()\n            {\n                EditorGUILayout.EndHorizontal();\n            }\n        }\n\n        public class ScrollView : System.IDisposable\n        {\n            public ScrollView(ref Vector2 pos)\n            {\n                pos = EditorGUILayout.BeginScrollView(pos);\n            }\n\n            public void Dispose()\n            {\n                EditorGUILayout.EndScrollView();\n            }\n        }\n\n        public class HorizontalLayout : System.IDisposable\n        {\n            private bool centered;\n\n            public HorizontalLayout(bool centered = false, params GUILayoutOption[] options)\n            {\n                this.centered = centered;\n                EditorGUILayout.BeginHorizontal(options);\n                if (centered) GUILayout.FlexibleSpace();\n            }\n\n            public void Dispose()\n            {\n                if (centered) GUILayout.FlexibleSpace();\n                EditorGUILayout.EndHorizontal();\n            }\n        }\n\n        public class VerticalLayout : System.IDisposable\n        {\n            public VerticalLayout(params GUILayoutOption[] options)\n            {\n                EditorGUILayout.BeginVertical(options);\n            }\n\n            public void Dispose()\n            {\n                EditorGUILayout.EndVertical();\n            }\n        }\n\n        public class LabelWidth : System.IDisposable\n        {\n            float originalWidth;\n\n            public LabelWidth(float width)\n            {\n                originalWidth = EditorGUIUtility.labelWidth;\n                EditorGUIUtility.labelWidth = width;\n            }\n\n            public void Dispose()\n            {\n                EditorGUIUtility.labelWidth = originalWidth;\n            }\n        }\n\n        public class Indent : System.IDisposable\n        {\n            int indent;\n\n            public Indent(int indent = 1)\n            {\n                this.indent = indent;\n                EditorGUI.indentLevel += indent;\n            }\n\n            public void Dispose()\n            {\n                EditorGUI.indentLevel -= indent;\n            }\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorGUIUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d009654f54214548a829eb95f493f3f6\ntimeCreated: 1658972649"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorGeneric.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Newtonsoft.Json.Serialization;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.UI;\n\nnamespace VirtueSky.UtilsEditor\n{\n    public static class EditorExtend\n    {\n        public static Rect GetInnerGuiPosition(SceneView sceneView)\n        {\n            var position = sceneView.position;\n            position.x = position.y = 0;\n            position.height -= EditorStyles.toolbar.fixedHeight;\n            return position;\n        }\n\n        public static bool Get2DMouseScenePosition(out Vector2 result)\n        {\n            result = Vector2.zero;\n\n            var cam = Camera.current;\n            if (cam == null) return false;\n\n            var guiMouse = Event.current.mousePosition;\n            var pixelMouse = guiMouse * EditorGUIUtility.pixelsPerPoint;\n            pixelMouse.y = cam.pixelHeight - pixelMouse.y; // không dùng Screen.height!\n\n            var ray = cam.ScreenPointToRay(pixelMouse);\n            if (ray.direction != Vector3.forward) return false;\n\n            result = ray.origin;\n            return true;\n        }\n\n\n        /// <summary>\n        /// Render an object on sceneView using sprite renderers\n        /// </summary>\n        public static void FakeRenderSprite(GameObject obs, Vector3 position, Vector3 scale, Quaternion rotation)\n        {\n            var rends = obs.GetComponentsInChildren<SpriteRenderer>();\n            foreach (var rend in rends)\n            {\n                var bounds = rend.bounds;\n                var pos = rend.transform.position - obs.transform.position + position;\n                DrawSprite(rend.sprite, pos, Vector3.Scale(bounds.size, scale));\n            }\n        }\n\n        private static void DrawSprite(Sprite sprite, Vector3 worldSpace, Vector3 size)\n        {\n            if (sprite == null) return;\n            Rect spriteTextureRect = LocalTextureRect(sprite);\n\n            Handles.BeginGUI();\n\n            Vector2 v0 = HandleUtility.WorldToGUIPoint(worldSpace - size / 2f);\n            Vector2 v1 = HandleUtility.WorldToGUIPoint(worldSpace + size / 2f);\n            Vector2 vMin = new Vector2(Mathf.Min(v0.x, v1.x), Mathf.Min(v0.y, v1.y));\n            Vector2 vMax = new Vector2(Mathf.Max(v0.x, v1.x), Mathf.Max(v0.y, v1.y));\n            Rect r = new Rect(vMin, vMax - vMin);\n            GUI.DrawTextureWithTexCoords(r, sprite.texture, spriteTextureRect);\n\n            Handles.EndGUI();\n        }\n\n        /// <summary>\n        /// Calculate normalized texturerect of a sprite (0->1)\n        /// </summary>\n        private static Rect LocalTextureRect(Sprite sprite)\n        {\n            var texturePosition = sprite.textureRect.position;\n            var textureSize = sprite.textureRect.size;\n            texturePosition.x /= sprite.texture.width;\n            texturePosition.y /= sprite.texture.height;\n            textureSize.x /= sprite.texture.width;\n            textureSize.y /= sprite.texture.height;\n            return new Rect(texturePosition, textureSize);\n        }\n\n        public static void SkipEvent()\n        {\n            int id = GUIUtility.GetControlID(FocusType.Passive);\n            GUIUtility.hotControl = id;\n            HandleUtility.AddDefaultControl(id);\n            Event.current.Use();\n        }\n\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"root\"></param>\n        /// <param name=\"bounds\"></param>\n        /// <param name=\"space\"></param>\n        /// <param name=\"renderers\"></param>\n        /// <param name=\"colliders\"></param>\n        /// <param name=\"meshes\"></param>\n        /// <param name=\"graphics\"></param>\n        /// <param name=\"particles\"></param>\n        /// <returns></returns>\n        public static bool CalculateBounds(\n            this GameObject root,\n            out Bounds bounds,\n            Space space,\n            bool renderers = true,\n            bool colliders = true,\n            bool meshes = false,\n            bool graphics = true,\n            bool particles = false)\n        {\n            bounds = new Bounds();\n\n            var first = true;\n\n            if (space == Space.Self)\n            {\n                if (renderers)\n                {\n                    var results = new List<Renderer>();\n                    root.GetComponentsInChildren(results);\n\n                    foreach (var renderer in results)\n                    {\n                        if (!renderer.enabled)\n                        {\n                            continue;\n                        }\n\n                        if (!particles && renderer is ParticleSystemRenderer)\n                        {\n                            continue;\n                        }\n\n                        var rendererBounds = renderer.bounds;\n\n                        rendererBounds.SetMinMax(root.transform.InverseTransformPoint(rendererBounds.min),\n                            root.transform.InverseTransformPoint(rendererBounds.max));\n\n                        if (first)\n                        {\n                            bounds = rendererBounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(rendererBounds);\n                        }\n                    }\n\n                    results = null;\n                }\n\n                if (meshes)\n                {\n                    var meshFilters = new List<MeshFilter>();\n                    root.GetComponentsInChildren(meshFilters);\n\n                    foreach (var meshFilter in meshFilters)\n                    {\n                        var mesh = Application.isPlaying ? meshFilter.mesh : meshFilter.sharedMesh;\n\n                        if (mesh == null)\n                        {\n                            continue;\n                        }\n\n                        var meshBounds = mesh.bounds;\n\n                        meshBounds.SetMinMax(\n                            root.transform.InverseTransformPoint(meshFilter.transform.TransformPoint(meshBounds.min)),\n                            root.transform.InverseTransformPoint(meshFilter.transform.TransformPoint(meshBounds.max)));\n\n                        if (first)\n                        {\n                            bounds = meshBounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(meshBounds);\n                        }\n                    }\n\n                    meshFilters = null;\n                }\n\n                if (graphics)\n                {\n                    var results = new List<Graphic>();\n                    root.GetComponentsInChildren(results);\n\n                    foreach (var graphic in results)\n                    {\n                        if (!graphic.enabled)\n                        {\n                            continue;\n                        }\n\n                        var graphicCorners = new Vector3[4] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };\n                        graphic.rectTransform.GetLocalCorners(graphicCorners);\n                        var graphicsBounds = BoundsFromCorners(graphicCorners);\n                        graphicCorners = null;\n\n                        if (first)\n                        {\n                            bounds = graphicsBounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(graphicsBounds);\n                        }\n                    }\n\n                    results = null;\n                }\n\n                if (colliders && first)\n                {\n                    var results = new List<Collider>();\n                    root.GetComponentsInChildren(results);\n\n                    foreach (var collider in results)\n                    {\n                        if (!collider.enabled)\n                        {\n                            continue;\n                        }\n\n                        var colliderBounds = collider.bounds;\n\n                        colliderBounds.SetMinMax(root.transform.InverseTransformPoint(colliderBounds.min),\n                            root.transform.InverseTransformPoint(colliderBounds.max));\n\n                        if (first)\n                        {\n                            bounds = colliderBounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(colliderBounds);\n                        }\n                    }\n\n                    results = null;\n                }\n\n                return !first;\n            }\n            else // if (space == Space.World)\n            {\n                if (renderers)\n                {\n                    var results = new List<Renderer>();\n                    root.GetComponentsInChildren(results);\n\n                    foreach (var renderer in results)\n                    {\n                        if (!renderer.enabled)\n                        {\n                            continue;\n                        }\n\n                        if (!particles && renderer is ParticleSystemRenderer)\n                        {\n                            continue;\n                        }\n\n                        if (first)\n                        {\n                            bounds = renderer.bounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(renderer.bounds);\n                        }\n                    }\n\n                    results = null;\n                }\n\n                if (meshes)\n                {\n                    var filters = new List<MeshFilter>();\n                    root.GetComponentsInChildren(filters);\n\n                    foreach (var meshFilter in filters)\n                    {\n                        var mesh = (Application.isPlaying ? meshFilter.mesh : meshFilter.sharedMesh);\n\n                        if (mesh == null)\n                        {\n                            continue;\n                        }\n\n                        var meshBounds = mesh.bounds;\n\n                        meshBounds.SetMinMax(root.transform.TransformPoint(meshBounds.min),\n                            root.transform.TransformPoint(meshBounds.max));\n\n                        if (first)\n                        {\n                            bounds = meshBounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(meshBounds);\n                        }\n                    }\n\n                    filters = null;\n                }\n\n                if (graphics)\n                {\n                    var results = new List<Graphic>();\n                    root.GetComponentsInChildren(results);\n\n                    foreach (var graphic in results)\n                    {\n                        if (!graphic.enabled)\n                        {\n                            continue;\n                        }\n\n                        var graphicCorners = new Vector3[4] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };\n                        graphic.rectTransform.GetWorldCorners(graphicCorners);\n                        var graphicsBounds = BoundsFromCorners(graphicCorners);\n                        graphicCorners = null;\n\n                        if (first)\n                        {\n                            bounds = graphicsBounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(graphicsBounds);\n                        }\n                    }\n\n                    results = null;\n                }\n\n                if (colliders && first)\n                {\n                    var results = new List<Collider>();\n                    root.GetComponentsInChildren(results);\n\n                    foreach (var collider in results)\n                    {\n                        if (!collider.enabled)\n                        {\n                            continue;\n                        }\n\n                        if (first)\n                        {\n                            bounds = collider.bounds;\n                            first = false;\n                        }\n                        else\n                        {\n                            bounds.Encapsulate(collider.bounds);\n                        }\n                    }\n\n                    results = null;\n                }\n            }\n\n            return !first;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"corners\"></param>\n        /// <returns></returns>\n        private static Bounds BoundsFromCorners(Vector3[] corners)\n        {\n            var minX = float.MaxValue;\n            var minY = float.MaxValue;\n            var minZ = float.MaxValue;\n\n            var maxX = float.MinValue;\n            var maxY = float.MinValue;\n            var maxZ = float.MinValue;\n\n            foreach (var corner in corners)\n            {\n                if (corner.x < minX)\n                {\n                    minX = corner.x;\n                }\n\n                if (corner.y < minY)\n                {\n                    minY = corner.y;\n                }\n\n                if (corner.z < minZ)\n                {\n                    minZ = corner.z;\n                }\n\n                if (corner.x > minX)\n                {\n                    maxX = corner.x;\n                }\n\n                if (corner.y > minY)\n                {\n                    maxY = corner.y;\n                }\n\n                if (corner.z > minZ)\n                {\n                    maxZ = corner.z;\n                }\n            }\n\n            return new Bounds() { min = new Vector3(minX, minY, minZ), max = new Vector3(maxX, maxY, maxZ) };\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <returns></returns>\n        public static string ToCamelCase(this string source)\n        {\n            return new CamelCaseNamingStrategy().GetPropertyName(source, false);\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <returns></returns>\n        public static string ToSnackCase(this string source)\n        {\n            return new SnakeCaseNamingStrategy().GetPropertyName(source, false);\n        }\n\n        public static bool IsSerializable(Type type)\n        {\n            var isSerializable = false;\n            isSerializable |= type.IsSerializable;\n            isSerializable |= type.Namespace == \"UnityEngine\";\n            isSerializable |= type.IsSubclassOf(typeof(MonoBehaviour));\n            return isSerializable;\n        }\n\n        public static void DrawSerializationError(Type type, Rect position = default)\n        {\n            if (position == default)\n            {\n                EditorGUILayout.HelpBox(\n                    $\"{type} is not marked as Serializable,\" + \"\\n Add [System.Serializable] attribute.\",\n                    MessageType.Error);\n            }\n            else\n            {\n                var icon = EditorGUIUtility.IconContent(\"Error\").image;\n                GUI.DrawTexture(position, icon, ScaleMode.ScaleToFit);\n            }\n        }\n\n        /// <summary>\n        /// check if given type is array or list\n        /// </summary>\n        /// <param name=\"type\"></param>\n        /// <returns></returns>\n        public static bool IsCollectionType(this Type type)\n        {\n            return type.IsArray || type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>);\n        }\n\n        public static Type GetCorrectElementType(this Type type)\n        {\n            if (type.IsArray)\n            {\n                return type.GetElementType();\n            }\n\n            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))\n            {\n                return type.GetGenericArguments()[0];\n            }\n\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorGeneric.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ad38d87efa33406cac5633aa2a491d46\ntimeCreated: 1697172720"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorResources.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.UtilsEditor\n{\n    public static class EditorResources\n    {\n        private const string RELATIVE_PATH = \"VirtueSky/Utils/Editor/Icons\";\n\n        public static Texture2D BoxContentDark =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"box_content_dark.psd\", RELATIVE_PATH);\n\n        public static Texture2D BoxBackgroundDark =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"box_bg_dark.psd\", RELATIVE_PATH);\n\n        public static Texture2D EvenBackground =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"even_bg.png\", RELATIVE_PATH);\n\n        public static Texture2D EvenBackgroundBlue =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"even_bg_select.png\", RELATIVE_PATH);\n\n        public static Texture2D EvenBackgroundDark =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"even_bg_dark.png\", RELATIVE_PATH);\n\n        public static Texture2D ScriptableFactory =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"scriptable_factory.png\", RELATIVE_PATH);\n\n        public static Texture2D IconAds => FileExtension.FindAssetWithPath<Texture2D>(\"icon_ads.png\", RELATIVE_PATH);\n        public static Texture2D IconIap => FileExtension.FindAssetWithPath<Texture2D>(\"icon_iap.png\", RELATIVE_PATH);\n        public static Texture2D IconLocale => FileExtension.FindAssetWithPath<Texture2D>(\"icon_locale.png\", RELATIVE_PATH);\n\n        public static Texture2D IconScriptableEvent =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"scriptable_event.png\", RELATIVE_PATH);\n\n        public static Texture2D IconScriptableVariable =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"scriptable_variable.png\", RELATIVE_PATH);\n\n        public static Texture2D IconAudio =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_audio.png\", RELATIVE_PATH);\n\n        public static Texture2D IconFirebase =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_firebase.png\", RELATIVE_PATH);\n\n        public static Texture2D IconAdjust =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_adjust.png\", RELATIVE_PATH);\n\n        public static Texture2D IconAppsFlyer =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_appsflyer.png\", RELATIVE_PATH);\n\n\n        public static Texture2D IconInAppReview =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_in_app_review.png\", RELATIVE_PATH);\n\n\n        public static Texture2D IconGameService =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_game_service.png\", RELATIVE_PATH);\n\n        public static Texture2D IconFolder =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_folder.png\", RELATIVE_PATH);\n\n        public static Texture2D IconHierarchy =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_hierarchy.png\", RELATIVE_PATH);\n\n        public static Texture2D IconPushNotification =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"script_noti.png\", RELATIVE_PATH);\n\n        public static Texture2D IconUnity =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_unity.png\", RELATIVE_PATH);\n\n        public static Texture2D IconExtension =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_extension.png\", RELATIVE_PATH);\n\n        public static Texture2D IconPackage =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_package.png\", RELATIVE_PATH);\n\n        public static Texture2D IconAbout =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"icon_about.png\", RELATIVE_PATH);\n\n        public static Texture2D IconVirtueSky =>\n            FileExtension.FindAssetWithPath<Texture2D>(\"virtuesky_removebg.png\", RELATIVE_PATH);\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorResources.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a3357bcdcfbe439d877bd5c4507167fa\ntimeCreated: 1697172101"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorScriptDefineSymbols.cs",
    "content": "﻿#if UNITY_EDITOR\nusing System.Linq;\nusing UnityEditor;\n\nnamespace VirtueSky.UtilsEditor\n{\n    public class EditorScriptDefineSymbols : EditorWindow\n    {\n        private const string defaultMenuPath = \"Sunflower/ScriptDefineSymbols/\";\n\n        // #region Ads\n        //\n        // private const string menuPathAds = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ADS;\n        //\n        // [MenuItem(menuPathAds)]\n        // public static void AdsConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ADS);\n        // }\n        //\n        // [MenuItem(menuPathAds, true)]\n        // public static bool IsAdsConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAds, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ADS));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Applovin\n        //\n        // private const string menuPathApplovin = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_APPLOVIN;\n        //\n        // [MenuItem(menuPathApplovin)]\n        // public static void ApplovinConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_APPLOVIN);\n        // }\n        //\n        // [MenuItem(menuPathApplovin, true)]\n        // public static bool IsApplovinConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathApplovin, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_APPLOVIN));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Admob\n        //\n        // private const string menuPathAdmob = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ADMOB;\n        //\n        // [MenuItem(menuPathAdmob)]\n        // public static void AdmobConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ADMOB);\n        // }\n        //\n        // [MenuItem(menuPathAdmob, true)]\n        // public static bool IsAdmobConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAdmob, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ADMOB));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Adjust\n        //\n        // private const string menuPathAdjust = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ADJUST;\n        //\n        // [MenuItem(menuPathAdjust)]\n        // public static void AdjustConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ADJUST);\n        // }\n        //\n        // [MenuItem(menuPathAdjust, true)]\n        // public static bool IsAdjustConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAdjust, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ADJUST));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Firebase Analytics\n        //\n        // private const string menuPathAnalytic = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC;\n        //\n        // [MenuItem(menuPathAnalytic)]\n        // public static void AnalyticConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC);\n        // }\n        //\n        // [MenuItem(menuPathAnalytic, true)]\n        // public static bool IsAnalyticConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAnalytic, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_FIREBASE_ANALYTIC));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Firebase Remote Config\n        //\n        // private const string menuPathRemoteConfig =\n        //     defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG;\n        //\n        // [MenuItem(menuPathRemoteConfig)]\n        // public static void RemoteConfigConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG);\n        // }\n        //\n        // [MenuItem(menuPathRemoteConfig, true)]\n        // public static bool IsRemoteConfigConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathRemoteConfig, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_FIREBASE_REMOTECONFIG));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Firebase App\n        //\n        // private const string menuPathFirebaseApp = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_FIREBASE;\n        //\n        // [MenuItem(menuPathFirebaseApp)]\n        // public static void FirebaseAppConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_FIREBASE);\n        // }\n        //\n        // [MenuItem(menuPathFirebaseApp, true)]\n        // public static bool IsFirebaseAppConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathFirebaseApp, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_FIREBASE));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Iap\n        //\n        // private const string menuPathIAP = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_IAP;\n        //\n        // [MenuItem(menuPathIAP)]\n        // public static void IapConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_IAP);\n        // }\n        //\n        // [MenuItem(menuPathIAP, true)]\n        // public static bool IsIapFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathIAP, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_IAP));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Ratting\n        //\n        // private const string menuPathRatting = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_RATING;\n        //\n        // [MenuItem(menuPathRatting)]\n        // public static void RattingConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_RATING);\n        // }\n        //\n        // [MenuItem(menuPathRatting, true)]\n        // public static bool IsRattingConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathRatting, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_RATING));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Notification\n        //\n        // private const string menuPathNotification = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_NOTIFICATION;\n        //\n        // [MenuItem(menuPathNotification)]\n        // public static void NotificationConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION);\n        // }\n        //\n        // [MenuItem(menuPathNotification, true)]\n        // public static bool IsNotificationConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathNotification, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_NOTIFICATION));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region AppsFlyer\n        //\n        // private const string menuPathAppsFlyer = defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_APPSFLYER;\n        //\n        // [MenuItem(menuPathAppsFlyer)]\n        // public static void AppsFlyerConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_APPSFLYER);\n        // }\n        //\n        // [MenuItem(menuPathAppsFlyer, true)]\n        // public static bool IsAppsFlyerConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAppsFlyer, IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_APPSFLYER));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region PRIME_TWEEN_DOTWEEN_ADAPTER\n        //\n        // private const string menuPathPrimeTweenDotweenAdapter =\n        //     defaultMenuPath + ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER;\n        //\n        // [MenuItem(menuPathPrimeTweenDotweenAdapter)]\n        // public static void PrimeTweenDoTweenAdapterConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER);\n        // }\n        //\n        // [MenuItem(menuPathPrimeTweenDotweenAdapter, true)]\n        // public static bool IsPrimeTweenDoTweenAdapterConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathPrimeTweenDotweenAdapter,\n        //         IsFlagEnabled(ConstantDefineSymbols.PRIME_TWEEN_DOTWEEN_ADAPTER));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region GPGS\n        //\n        // private const string menuPathGPGS =\n        //     defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_GPGS;\n        //\n        // [MenuItem(menuPathGPGS)]\n        // public static void GPGSConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_GPGS);\n        // }\n        //\n        // [MenuItem(menuPathGPGS, true)]\n        // public static bool IsGPGSConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathGPGS,\n        //         IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_GPGS));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Apple Auth\n        //\n        // private const string menuPathAppleAuth =\n        //     defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH;\n        //\n        // [MenuItem(menuPathAppleAuth)]\n        // public static void AppleAuthConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH);\n        // }\n        //\n        // [MenuItem(menuPathAppleAuth, true)]\n        // public static bool IsAppleAuthConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAppleAuth,\n        //         IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_APPLE_AUTH));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Skeleton\n        //\n        // private const string menuPathSkeleton =\n        //     defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_SKELETON;\n        //\n        // [MenuItem(menuPathSkeleton)]\n        // public static void SkeletonConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_SKELETON);\n        // }\n        //\n        // [MenuItem(menuPathSkeleton, true)]\n        // public static bool IsSkeletonConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAppleAuth,\n        //         IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_SKELETON));\n        //     return true;\n        // }\n        //\n        // #endregion\n        //\n        // #region Animancer\n        //\n        // private const string menuPathAnimancer =\n        //     defaultMenuPath + ConstantDefineSymbols.VIRTUESKY_ANIMANCER;\n        //\n        // [MenuItem(menuPathAnimancer)]\n        // public static void AnimancerConfigFlag()\n        // {\n        //     SwitchFlag(ConstantDefineSymbols.VIRTUESKY_ANIMANCER);\n        // }\n        //\n        // [MenuItem(menuPathAnimancer, true)]\n        // public static bool IsAnimancerConfigFlagEnable()\n        // {\n        //     Menu.SetChecked(menuPathAppleAuth,\n        //         IsFlagEnabled(ConstantDefineSymbols.VIRTUESKY_ANIMANCER));\n        //     return true;\n        // }\n        //\n        // #endregion\n\n        #region Base Functions\n\n        public static void SwitchFlag(string flag)\n        {\n            PlayerSettings.GetScriptingDefineSymbolsForGroup(\n                EditorUserBuildSettings.selectedBuildTargetGroup,\n                out var defines);\n            var enabled = defines.Contains(flag);\n            defines = enabled\n                ? defines.Where(value => value != flag).ToArray()\n                : defines.Append(flag).ToArray();\n            PlayerSettings.SetScriptingDefineSymbolsForGroup(\n                EditorUserBuildSettings.selectedBuildTargetGroup, defines);\n        }\n\n        public static bool IsFlagEnabled(string flag)\n        {\n            PlayerSettings.GetScriptingDefineSymbolsForGroup(\n                EditorUserBuildSettings.selectedBuildTargetGroup,\n                out var defines);\n            return defines.Contains(flag);\n        }\n\n        #endregion\n    }\n}\n#endif"
  },
  {
    "path": "VirtueSky/Utils/Editor/EditorScriptDefineSymbols.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aa1b7f49165047aab9cd98879dd2af84\ntimeCreated: 1697165306"
  },
  {
    "path": "VirtueSky/Utils/Editor/ExSearchWindow.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor.Experimental.GraphView;\nusing UnityEngine;\n\nnamespace VirtueSky.UtilsEditor\n{\n    public class ExSearchWindow : ScriptableObject, ISearchWindowProvider\n    {\n        [Flags]\n        public enum SortType\n        {\n            None = 0,\n            Directory = 1,\n            Alphabet = 2\n        }\n\n        private struct Entry\n        {\n            public readonly GUIContent content;\n            public readonly object data;\n            public readonly Action<object> onSelect;\n\n            public Entry(GUIContent content, object data, Action<object> onSelect)\n            {\n                this.content = content;\n                this.data = data;\n                this.onSelect = onSelect;\n            }\n        }\n\n        private string title = string.Empty;\n        private Texture2D emptyIcon;\n        private SortType sortType = SortType.Directory | SortType.Alphabet;\n        private List<Entry> entries = new List<Entry>();\n\n        /// <summary>\n        /// Generates data to populate the search window.\n        /// </summary>\n        /// <param name=\"context\">Contextual data initially passed the window when first created.</param>\n        /// <returns>Returns the list of SearchTreeEntry objects displayed in the search window.</returns>\n        public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)\n        {\n            if (sortType != SortType.None)\n            {\n                entries.Sort(SortEntriesByGroup);\n            }\n\n            List<SearchTreeEntry> treeEntries = new List<SearchTreeEntry>() {new SearchTreeGroupEntry(new GUIContent(title), 0)};\n\n            List<string> groups = new List<string>();\n            for (int i = 0; i < entries.Count; i++)\n            {\n                Entry entry = entries[i];\n\n                string group = string.Empty;\n                string[] paths = entry.content.text.Split('/');\n                int length = paths.Length - 1;\n                for (int j = 0; j < length; j++)\n                {\n                    string path = paths[j];\n\n                    group += path;\n                    if (!groups.Contains(group))\n                    {\n                        treeEntries.Add(new SearchTreeGroupEntry(new GUIContent(path), j + 1));\n                        groups.Add(group);\n                    }\n\n                    group += \"/\";\n                }\n\n                entry.content.text = paths[length];\n                SearchTreeEntry searchTreeEntry = new SearchTreeEntry(entry.content);\n                searchTreeEntry.userData = i;\n                searchTreeEntry.level = paths.Length;\n                treeEntries.Add(searchTreeEntry);\n            }\n\n            return treeEntries;\n        }\n\n        /// <summary>\n        /// Selects an entry in the search tree list.\n        /// </summary>\n        /// <param name=\"searchTreeEntry\">The selected entry.</param>\n        /// <param name=\"context\">Contextual data to pass to the search window when it is first created.</param>\n        public bool OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context)\n        {\n            Entry entry = entries[(int) searchTreeEntry.userData];\n            if (entry.onSelect != null)\n            {\n                entry.onSelect.Invoke(entry.data);\n                return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Add new entry.\n        /// </summary>\n        /// <param name=\"content\">The text and icon of the search entry.</param>\n        /// <param name=\"data\">A user specified object for attaching application specific data to a search tree entry.</param>\n        /// <param name=\"onSelect\">Action with data argument, which called after entry is selected.</param>\n        public void AddEntry(GUIContent content, object data, Action<object> onSelect) { entries.Add(new Entry(content, data, onSelect)); }\n\n        /// <summary>\n        /// Add new entry.\n        /// </summary>\n        /// <param name=\"content\">The text and icon of the search entry.</param>\n        /// <param name=\"onSelect\">Action which called after entry is selected.</param>\n        public void AddEntry(GUIContent content, Action onSelect) { entries.Add(new Entry(content, null, (data) => onSelect?.Invoke())); }\n\n        /// <summary>\n        /// Add new entry.\n        /// </summary>\n        /// <param name=\"name\">The name of the search entry.</param>\n        /// <param name=\"data\">A user specified object for attaching application specific data to a search tree entry.</param>\n        /// <param name=\"onSelect\">Action with data argument, which called after entry is selected.</param>\n        public void AddEntry(string name, object data, Action<object> onSelect) { AddEntry(new GUIContent(name), data, onSelect); }\n\n        /// <summary>\n        /// Add new entry.\n        /// </summary>\n        /// <param name=\"name\">The name of the search entry.</param>\n        /// <param name=\"onSelect\">Action which called after entry is selected.</param>\n        public void AddEntry(string name, Action onSelect) { AddEntry(new GUIContent(name), null, (data) => onSelect?.Invoke()); }\n\n        /// <summary>\n        /// Add new indented entity.\n        /// </summary>\n        /// <param name=\"name\">Name of none label.</param>\n        /// <param name=\"onSelect\">Action which called after entry is selected.</param>\n        public void AddEntityIndented(string name, Action onSelect)\n        {\n            GUIContent content = new GUIContent(name, GetEmptyIcon());\n            AddEntry(content, onSelect);\n        }\n\n        /// <summary>\n        /// Add new indented entity.\n        /// </summary>\n        /// <param name=\"name\">Name of none label.</param>\n        /// <param name=\"data\">A user specified object for attaching application specific data to a search tree entry.</param>\n        /// <param name=\"onSelect\">Action with data argument, which called after entry is selected.</param>\n        public void AddEntityIndented(string name, object data, Action<object> onSelect)\n        {\n            GUIContent content = new GUIContent(name, GetEmptyIcon());\n            AddEntry(content, data, onSelect);\n        }\n\n\n        /// <summary>\n        /// Open search window.\n        /// </summary>\n        /// <param name=\"position\">Window position in screen space.</param>\n        /// <param name=\"width\">Requested width of the window. Set to 0.0f to use the default width.</param>\n        /// <param name=\"height\">Requested height of the window. Set to 0.0f to use the default height.</param>\n        public void Open(Vector2 position, float width = 0, float height = 0) { SearchWindow.Open(new SearchWindowContext(position, width, height), this); }\n\n        /// <summary>\n        /// Open search window in mouse position.\n        /// </summary>\n        /// <param name=\"width\">Requested width of the window. Set to 0.0f to use the default width.</param>\n        /// <param name=\"height\">Requested height of the window. Set to 0.0f to use the default height.</param>\n        public void Open(float width = 0, float height = 0)\n        {\n            Vector2 position = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);\n            Open(position, width, height);\n        }\n\n        /// <summary>\n        /// Open search window in button position.\n        /// </summary>\n        /// <param name=\"buttonRect\">Rectangle of GUI button.</param>\n        /// <param name=\"width\">Requested width of the window. Set to 0.0f to use the button width.</param>\n        /// <param name=\"height\">Requested height of the window. Set to 0.0f to use the default height.</param>\n        public void Open(Rect buttonRect, float width = 0, float height = 0)\n        {\n            Rect screenRect = GUIUtility.GUIToScreenRect(buttonRect);\n\n            Vector2 position = screenRect.position;\n            position.x += screenRect.width / 2;\n            position.y += screenRect.height + 15;\n\n            width = Mathf.Max(0, width);\n            width = width != 0 ? width : screenRect.width;\n\n            Open(position, width != 0 ? width : screenRect.width, height);\n        }\n\n        /// <summary>\n        /// Sort entries by paths.\n        /// </summary>\n        /// <param name=\"lhs\">Left hand side entry.</param>\n        /// <param name=\"rhs\">Right hand side entry.</param>\n        private int SortEntriesByGroup(Entry lhs, Entry rhs)\n        {\n            string[] lhsPaths = lhs.content.text.Split('/');\n            string[] rhsPaths = rhs.content.text.Split('/');\n\n            int lhsLength = lhsPaths.Length;\n            int rhsLength = rhsPaths.Length;\n            int minLength = Mathf.Min(lhsLength, rhsLength);\n\n            for (int i = 0; i < minLength; i++)\n            {\n                if ((sortType & SortType.Directory) != 0)\n                {\n                    if (minLength - 1 == i)\n                    {\n                        int compareDepth = rhsLength.CompareTo(lhsLength);\n                        if (compareDepth != 0)\n                        {\n                            return compareDepth;\n                        }\n                    }\n                }\n\n                if ((sortType & SortType.Alphabet) != 0)\n                {\n                    int compareText = lhsPaths[i].CompareTo(rhsPaths[i]);\n                    if (compareText != 0)\n                    {\n                        return compareText;\n                    }\n                }\n            }\n\n            return 0;\n        }\n\n        /// <summary>\n        /// Get empty icon.\n        /// </summary>\n        private Texture GetEmptyIcon()\n        {\n            if (emptyIcon == null)\n            {\n                emptyIcon = new Texture2D(1, 1);\n                emptyIcon.SetPixel(0, 0, Color.clear);\n                emptyIcon.Apply();\n            }\n\n            return emptyIcon;\n        }\n\n        #region [Static Methods]\n\n        /// <summary>\n        /// Create ExLib search window.\n        /// </summary>\n        /// <param name=\"title\">Window title.</param>\n        /// <returns>ExSearchWindow instance.</returns>\n        public static ExSearchWindow Create(string title)\n        {\n            ExSearchWindow window = CreateInstance<ExSearchWindow>();\n            window.SetTitle(title);\n            return window;\n        }\n\n        /// <summary>\n        /// Create ExLib search window.\n        /// </summary>\n        /// <returns>ExSearchWindow instance.</returns>\n        public static ExSearchWindow Create()\n        {\n            const string TITLE = \"Entries\";\n            return Create(TITLE);\n        }\n\n        #endregion\n\n        #region [Getter / Setter]\n\n        public string GetTitle() { return title; }\n\n        public void SetTitle(string value) { title = value; }\n\n        public SortType GetSortType() { return sortType; }\n\n        public void SetSortType(SortType value) { sortType = value; }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/ExSearchWindow.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f924140accc14c36ac089612348dea4e\ntimeCreated: 1729158618"
  },
  {
    "path": "VirtueSky/Utils/Editor/FileExtension.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n#if UNITY_EDITOR\nusing UnityEditor;\n#endif\nusing Newtonsoft.Json.Linq;\nusing Debug = UnityEngine.Debug;\n\nnamespace VirtueSky.UtilsEditor\n{\n#if UNITY_EDITOR\n    public static class FileExtension\n    {\n        public static List<T> FindAll<T>(string path) where T : Object\n        {\n            var results = new List<T>();\n            var filter = $\"t:{typeof(T).Name}\";\n            var assetNames = AssetDatabase.FindAssets(filter, new[] { path });\n\n            foreach (string assetName in assetNames)\n            {\n                var assetPath = AssetDatabase.GUIDToAssetPath(assetName);\n                var asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);\n                if (asset == null) continue;\n\n                results.Add(asset);\n            }\n\n            return results;\n        }\n\n        /// <summary>\n        /// Find all asset with type <typeparamref name=\"T\"/>\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        public static List<T> FindAll<T>() where T : Object\n        {\n            var results = new List<T>();\n            var filter = $\"t:{typeof(T).Name}\";\n            var assetNames = AssetDatabase.FindAssets(filter);\n\n            foreach (string assetName in assetNames)\n            {\n                var assetPath = AssetDatabase.GUIDToAssetPath(assetName);\n                var asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);\n                if (asset == null) continue;\n\n                results.Add(asset);\n            }\n\n            return results;\n        }\n\n        public static T FindAssetWithPath<T>(string fullPath) where T : Object\n        {\n            string path = GetPathFileInCurrentEnvironment(fullPath);\n            var t = AssetDatabase.LoadAssetAtPath(path, typeof(T));\n            if (t == null) Debug.LogError($\"Couldn't load the {nameof(T)} at path :{path}\");\n            return t as T;\n        }\n\n        public static T FindAssetWithPath<T>(string nameAsset, string relativePath) where T : Object\n        {\n            string path = AssetInPackagePath(relativePath, nameAsset);\n            var t = AssetDatabase.LoadAssetAtPath(path, typeof(T));\n            if (t == null) Debug.LogError($\"Couldn't load the {nameof(T)} at path :{path}\");\n            return t as T;\n        }\n\n        public static T[] FindAssetsWithPath<T>(string nameAsset, string relativePath)\n            where T : Object\n        {\n            string path = AssetInPackagePath(relativePath, nameAsset);\n            var t = AssetDatabase.LoadAllAssetsAtPath(path).OfType<T>().ToArray();\n            if (t.Length == 0) Debug.LogError($\"Couldn't load the {nameof(T)} at path :{path}\");\n            return t;\n        }\n\n        public static void ChangeAssetName(Object asset, string name)\n        {\n            var assetPath = AssetDatabase.GetAssetPath(asset.GetInstanceID());\n            AssetDatabase.RenameAsset(assetPath, name);\n            AssetDatabase.SaveAssets();\n        }\n\n        public static T[] FindAssetAtFolder<T>(string[] paths) where T : Object\n        {\n            var list = new List<T>();\n            var guids = AssetDatabase.FindAssets($\"t:{typeof(T).Name}\", paths);\n            foreach (var guid in guids)\n            {\n                var asset = AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(guid));\n                if (asset)\n                {\n                    list.Add(asset);\n                }\n            }\n\n            return list.ToArray();\n        }\n\n        public static T FindAssetAtResource<T>(string path) where T : ScriptableObject\n        {\n            T config =\n                Resources.Load<T>(path);\n            if (config != null)\n            {\n                return config;\n            }\n\n            return null;\n        }\n\n        public static string AssetInPackagePath(string relativePath, string nameAsset)\n        {\n            return GetPathFileInCurrentEnvironment($\"{relativePath}/{nameAsset}\");\n        }\n\n        public static string GetPathFileInCurrentEnvironment(string fullRelativePath)\n        {\n            var upmPath = $\"Packages/com.virtuesky.sunflower/{fullRelativePath}\";\n            var normalPath = $\"Assets/Sunflower/{fullRelativePath}\";\n            return !File.Exists(Path.GetFullPath(upmPath)) ? normalPath : upmPath;\n        }\n\n        public static string GetPathFolderInCurrentEnvironment(string fullRelativePath)\n        {\n            var upmPath = $\"Packages/com.virtuesky.sunflower/{fullRelativePath}\";\n            var normalPath = $\"Assets/Sunflower/{fullRelativePath}\";\n            return Directory.Exists(upmPath) ? upmPath : normalPath;\n        }\n\n        public static string FormatJson(string json)\n        {\n            try\n            {\n                JToken parsedJson = JToken.Parse(json);\n                return parsedJson.ToString(Newtonsoft.Json.Formatting.Indented);\n            }\n            catch (Exception)\n            {\n                return json;\n            }\n        }\n\n        public static string ManifestPath => Application.dataPath + \"/../Packages/manifest.json\";\n\n        public static void OpenFolderInExplorer(string path)\n        {\n            if (Directory.Exists(path))\n            {\n                Process.Start(path);\n            }\n            else\n            {\n                Debug.LogError(\"The directory does not exist: \" + path);\n            }\n        }\n\n        public static void OpenFolderInFinder(string path)\n        {\n            if (Directory.Exists(path))\n            {\n                Process.Start(\"open\", path);\n            }\n            else\n            {\n                Debug.LogError(\"The directory does not exist: \" + path);\n            }\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/FileExtension.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 856ea84c538240a281b59cffc972f392\ntimeCreated: 1694955555"
  },
  {
    "path": "VirtueSky/Utils/Editor/GameViewUtils.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing UnityEditor;\n\nnamespace VirtueSky.UtilsEditor\n{\n#if UNITY_EDITOR\n    public class GameViewUtils\n    {\n        public const int DefaultSizeCount = 18;\n\n        public static readonly Resolution[] resolutions =\n        {\n            new Resolution(\"iPhone 4\", 640, 960),\n            new Resolution(\"iPhone 5\", 640, 1136),\n            new Resolution(\"iPhone 6\", 750, 1334),\n            new Resolution(\"iPhone 8+\", 1242, 2208),\n            new Resolution(\"iPhone X\", 1125, 2436),\n            new Resolution(\"iPhone Xs Max\", 1242, 2688),\n            new Resolution(\"iPhone XR \", 828, 1792),\n            new Resolution(\"HD\", 1080, 1920),\n            new Resolution(\"iPad Retina\", 1536, 2048),\n            new Resolution(\"iPad Pro 10.5\", 1668, 2224),\n            new Resolution(\"iPad Pro 12.9\", 2048, 2732),\n            new Resolution(\"iPhone 11 Pro\", 1125, 2436),\n            new Resolution(\"iPhone 11 Pro Max\", 1242, 2688)\n        };\n\n        static readonly object gameViewSizesInstance;\n        static readonly MethodInfo getGroup;\n\n        static GameViewUtils()\n        {\n            var sizesType = typeof(Editor).Assembly.GetType(\"UnityEditor.GameViewSizes\");\n            var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);\n            var instanceProp = singleType.GetProperty(\"instance\");\n            getGroup = sizesType.GetMethod(\"GetGroup\");\n            gameViewSizesInstance = instanceProp.GetValue(null, null);\n        }\n\n        public static void AddCustomSize()\n        {\n            foreach (var resolution in resolutions)\n                AddCustomSize(GameViewSizeGroupType.Android, resolution.width, resolution.height, resolution.name);\n        }\n\n        static void AddCustomSize(GameViewSizeGroupType sizeGroupType, int width, int height, string text)\n        {\n            var group = GetGroup(sizeGroupType);\n            var addCustomSize = getGroup.ReturnType.GetMethod(\"AddCustomSize\");\n            var gvsType = typeof(UnityEditor.Editor).Assembly.GetType(\"UnityEditor.GameViewSize\");\n            var ctor = gvsType.GetConstructor(new[]\n            {\n                typeof(UnityEditor.Editor).Assembly.GetType(\"UnityEditor.GameViewSizeType\"), typeof(int), typeof(int),\n                typeof(string)\n            });\n            var newSize = ctor.Invoke(new object[] { 1, width, height, text });\n            addCustomSize.Invoke(group, new[] { newSize });\n        }\n\n        public static void SetSize(int index)\n        {\n            var gvWndType = typeof(Editor).Assembly.GetType(\"UnityEditor.GameView\");\n            var gvWnd = EditorWindow.GetWindow(gvWndType);\n            var sizeSelectionCallback = gvWndType.GetMethod(\"SizeSelectionCallback\",\n                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n            sizeSelectionCallback.Invoke(gvWnd, new object[] { index, null });\n        }\n\n        static object GetGroup(GameViewSizeGroupType type)\n        {\n            return getGroup.Invoke(gameViewSizesInstance, new object[] { (int)type });\n        }\n\n        public static int GetViewListSize()\n        {\n            var group = GetGroup(GameViewSizeGroupType.Android);\n            var getDisplayTexts = group.GetType().GetMethod(\"GetDisplayTexts\");\n            return (getDisplayTexts.Invoke(group, null) as string[]).Length;\n        }\n    }\n#endif\n\n\n    [Serializable]\n    public class Resolution\n    {\n        public string name;\n        public int height;\n        public int width;\n\n        public Resolution(string name, int width, int height)\n        {\n            this.name = name;\n            this.width = width;\n            this.height = height;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/GameViewUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 75154e8e7c6146cda787abf4cae97bd1\ntimeCreated: 1610554859"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/box_bg_dark.psd.meta",
    "content": "fileFormatVersion: 2\nguid: a0d7d4fd6c5588e42bf710818c91767a\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 12\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/box_content_dark.psd.meta",
    "content": "fileFormatVersion: 2\nguid: 7f8c595784dabd441b571229e95d48d0\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 12\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/even_bg.png.meta",
    "content": "fileFormatVersion: 2\nguid: c9c1e39bce5cc9349b0ccf76a9072a11\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 12\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/even_bg_dark.png.meta",
    "content": "fileFormatVersion: 2\nguid: c7e58306b400d5e49b4e8d6bdf56e7c8\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 12\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/even_bg_select.png.meta",
    "content": "fileFormatVersion: 2\nguid: 40593549b238df24b8a6dc7bc8b27e23\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 12\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_about.png.meta",
    "content": "fileFormatVersion: 2\nguid: 715151f76aa224d7ca98ecfca15e6507\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_adjust.png.meta",
    "content": "fileFormatVersion: 2\nguid: 4856817a41ca94c58b2293f27bee8195\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_ads.png.meta",
    "content": "fileFormatVersion: 2\nguid: 25c76aa4628f244f1aaf244096d3d3f0\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_appsflyer.png.meta",
    "content": "fileFormatVersion: 2\nguid: 927f854e1e4d440149078ed384de7fad\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_audio.png.meta",
    "content": "fileFormatVersion: 2\nguid: adf7179ddd730462c8344ae003135925\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_authentication.png.meta",
    "content": "fileFormatVersion: 2\nguid: e6bde4f6f44782647a9e30445fb10b74\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_button.png.meta",
    "content": "fileFormatVersion: 2\nguid: 64bffa989a83702458593189b3a27b57\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_controller.png.meta",
    "content": "fileFormatVersion: 2\nguid: 1c63e3b6583d6b54a8de6efcd2a86725\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_csharp.png.meta",
    "content": "fileFormatVersion: 2\nguid: f865308f7c963a749b9072d9efcd9bbf\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_extension.png.meta",
    "content": "fileFormatVersion: 2\nguid: 53c2c285c95cf478eaffc4727383342e\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_firebase.png.meta",
    "content": "fileFormatVersion: 2\nguid: 400ed70fe78e444ed8036fd7463efa70\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_folder.png.meta",
    "content": "fileFormatVersion: 2\nguid: e4deb87810b6041068305ddb7ed40b1b\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_game_service.png.meta",
    "content": "fileFormatVersion: 2\nguid: 96553426c05ac43e783c6fccc7ebda9e\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_gamemanager.png.meta",
    "content": "fileFormatVersion: 2\nguid: 86a9dd3493f67df4497023cb0db22e35\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_generator.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6d7560f524fe8e8419031f5b3d0fe423\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_hierarchy.png.meta",
    "content": "fileFormatVersion: 2\nguid: 422b56a3ea31444cd82f5ee33cbd31d4\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_iap.png.meta",
    "content": "fileFormatVersion: 2\nguid: 0035776e4532b40339ab2a226c3c02b2\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_in_app_review.png.meta",
    "content": "fileFormatVersion: 2\nguid: 920b61a4fece945abad438ca34e475e9\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_leaderboard.png.meta",
    "content": "fileFormatVersion: 2\nguid: 83412f62fe6dc9941959257e0ad3ad3b\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_locale.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6ac655bb225836f4a82eb8bcb32ebea8\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_manager.png.meta",
    "content": "fileFormatVersion: 2\nguid: 09a0b1cab6e2173438470729b45a73f1\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_package.png.meta",
    "content": "fileFormatVersion: 2\nguid: a3c56005701154c35aea721ecd1f579a\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_scriptable.png.meta",
    "content": "fileFormatVersion: 2\nguid: ed5ec0bb4ec55df47af0ecc2bd7be5f9\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 12\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_service.png.meta",
    "content": "fileFormatVersion: 2\nguid: 921eb218c6594e14b841e0aaf925a9cf\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 53\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_sound.png.meta",
    "content": "fileFormatVersion: 2\nguid: cf2f10eac3dea9342b741f19e985d1df\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_sound_mixer.png.meta",
    "content": "fileFormatVersion: 2\nguid: 23fb672e22185124e935486385bd367e\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 52\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/icon_unity.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6af62e0e4e89e4e9a9b14e5f1bfbe28f\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/script_noti.png.meta",
    "content": "fileFormatVersion: 2\nguid: 7e5f4750d7e998c40a41333bba35d8b8\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_adjust.png.meta",
    "content": "fileFormatVersion: 2\nguid: 1590f55a16087b747b4764e1a11fa320\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_adjust2.png.meta",
    "content": "fileFormatVersion: 2\nguid: b9157b0e91856514ba3f36deebb179cd\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_af.png.meta",
    "content": "fileFormatVersion: 2\nguid: 923d17c486919a945a5fef5ca1ee8e9b\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_audio.png.meta",
    "content": "fileFormatVersion: 2\nguid: f6fa313956d229647ad5911f1b5d081a\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_audioclip.png.meta",
    "content": "fileFormatVersion: 2\nguid: 3db558bebc410834889c3cdb93ca89b1\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_event.png.meta",
    "content": "fileFormatVersion: 2\nguid: 5ad7786ac7818964c9714ea071b638b3\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_event_listener.png.meta",
    "content": "fileFormatVersion: 2\nguid: 23cedf6c21faf0b4eb783f1fb5d4679a\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_factory.png.meta",
    "content": "fileFormatVersion: 2\nguid: 8c137c88e13ca774ca3189bd0f401c24\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_firebase.png.meta",
    "content": "fileFormatVersion: 2\nguid: c1bc3702a7695674fbddba3cae1c2a78\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_iap.png.meta",
    "content": "fileFormatVersion: 2\nguid: a7c0b6e003e41ca408cabaf952160992\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_notification.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6a4b74d7042712c41acccbc6d90305fd\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_particle_system.png.meta",
    "content": "fileFormatVersion: 2\nguid: cc343a292ab7f834eb6e7c664cc31a38\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 4\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 4\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 4\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    customData: \n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    spriteCustomMetadata:\n      entries: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_pool.png.meta",
    "content": "fileFormatVersion: 2\nguid: 9a1531ff57a958c4c92ab33ca22f62ef\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_variable.png.meta",
    "content": "fileFormatVersion: 2\nguid: 8f06818ab5c1c06439abc547979c8edd\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 0\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Server\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_audioclip.png.meta",
    "content": "fileFormatVersion: 2\nguid: 2579f1f676b7f2843a4cafaf429f9474\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_font.png.meta",
    "content": "fileFormatVersion: 2\nguid: 6612c7be3408486478603096058345a2\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_fontasset.png.meta",
    "content": "fileFormatVersion: 2\nguid: 120a98534767efd4ba0b7a9e91cda393\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_gameobject.png.meta",
    "content": "fileFormatVersion: 2\nguid: bfd31c3e578dee04295c2133a97be5dd\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_material.png.meta",
    "content": "fileFormatVersion: 2\nguid: 0bf47bf639988dc499e672dd3d0b7c26\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_sprite.png.meta",
    "content": "fileFormatVersion: 2\nguid: b2b3b70f4d3c0884faa424282862c6ca\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_text.png.meta",
    "content": "fileFormatVersion: 2\nguid: 13605300fcfb1fd45b49212af32ba2f8\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_textasset.png.meta",
    "content": "fileFormatVersion: 2\nguid: 5b605beec23f2f6408ce4cae4dedd075\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_texture.png.meta",
    "content": "fileFormatVersion: 2\nguid: a7f0847a6f95e2e46a76f375e4c2d001\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/scriptable_yellow_videoclip.png.meta",
    "content": "fileFormatVersion: 2\nguid: a3d36db6a75640543bcec2d532f8498d\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons/virtuesky_removebg.png.meta",
    "content": "fileFormatVersion: 2\nguid: 7a9683410876c4651adc20351e3e2c8d\nTextureImporter:\n  internalIDToNameTable: []\n  externalObjects: {}\n  serializedVersion: 13\n  mipmaps:\n    mipMapMode: 0\n    enableMipMap: 0\n    sRGBTexture: 1\n    linearTexture: 0\n    fadeOut: 0\n    borderMipMap: 0\n    mipMapsPreserveCoverage: 0\n    alphaTestReferenceValue: 0.5\n    mipMapFadeDistanceStart: 1\n    mipMapFadeDistanceEnd: 3\n  bumpmap:\n    convertToNormalMap: 0\n    externalNormalMap: 0\n    heightScale: 0.25\n    normalMapFilter: 0\n    flipGreenChannel: 0\n  isReadable: 0\n  streamingMipmaps: 0\n  streamingMipmapsPriority: 0\n  vTOnly: 0\n  ignoreMipmapLimit: 0\n  grayScaleToAlpha: 0\n  generateCubemap: 6\n  cubemapConvolution: 0\n  seamlessCubemap: 0\n  textureFormat: 1\n  maxTextureSize: 2048\n  textureSettings:\n    serializedVersion: 2\n    filterMode: 1\n    aniso: 1\n    mipBias: 0\n    wrapU: 1\n    wrapV: 1\n    wrapW: 0\n  nPOTScale: 0\n  lightmap: 0\n  compressionQuality: 50\n  spriteMode: 0\n  spriteExtrude: 1\n  spriteMeshType: 1\n  alignment: 0\n  spritePivot: {x: 0.5, y: 0.5}\n  spritePixelsToUnits: 100\n  spriteBorder: {x: 0, y: 0, z: 0, w: 0}\n  spriteGenerateFallbackPhysicsShape: 1\n  alphaUsage: 1\n  alphaIsTransparency: 1\n  spriteTessellationDetail: -1\n  textureType: 2\n  textureShape: 1\n  singleChannelComponent: 0\n  flipbookRows: 1\n  flipbookColumns: 1\n  maxTextureSizeSet: 0\n  compressionQualitySet: 0\n  textureFormatSet: 0\n  ignorePngGamma: 0\n  applyGammaDecoding: 0\n  swizzle: 50462976\n  cookieLightType: 0\n  platformSettings:\n  - serializedVersion: 3\n    buildTarget: DefaultTexturePlatform\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Standalone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: -1\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 0\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: iPhone\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 51\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  - serializedVersion: 3\n    buildTarget: Android\n    maxTextureSize: 2048\n    resizeAlgorithm: 0\n    textureFormat: 50\n    textureCompression: 1\n    compressionQuality: 50\n    crunchedCompression: 0\n    allowsAlphaSplitting: 0\n    overridden: 1\n    ignorePlatformSupport: 0\n    androidETC2FallbackOverride: 0\n    forceMaximumCompressionQuality_BC6H_BC7: 0\n  spriteSheet:\n    serializedVersion: 2\n    sprites: []\n    outline: []\n    physicsShape: []\n    bones: []\n    spriteID: \n    internalID: 0\n    vertices: []\n    indices: \n    edges: []\n    weights: []\n    secondaryTextures: []\n    nameFileIdTable: {}\n  mipmapLimitGroupName: \n  pSDRemoveMatte: 0\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Icons.meta",
    "content": "fileFormatVersion: 2\nguid: 9c1e9c5bf1a843c18bf32a98f6910ca3\ntimeCreated: 1697170213"
  },
  {
    "path": "VirtueSky/Utils/Editor/RegistryManager.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\nusing Newtonsoft.Json.Linq;\nusing UnityEditor.PackageManager;\nusing UnityEngine;\nusing VirtueSky.SimpleJSON;\n\n\nnamespace VirtueSky.UtilsEditor\n{\n    public static class RegistryManager\n    {\n        private static readonly string ManifestPath =\n            Path.Combine(Application.dataPath, \"..\", \"Packages\", \"manifest.json\");\n\n        public static void Add(string name, string version)\n        {\n            var json = JObject.Parse(File.ReadAllText(ManifestPath));\n            var dependencies = (JObject)json[\"dependencies\"];\n\n            if (dependencies != null)\n            {\n                foreach (var dependency in dependencies)\n                {\n                    if (dependency.Key.Equals(name)) return;\n                }\n\n                dependencies.Add(name, version);\n            }\n\n            Write(json);\n        }\n\n        public static void AddOverrideVersion(string name, string version)\n        {\n            (bool isInstall, string currentVersion) = IsInstalled(name);\n            if (currentVersion == \"\")\n            {\n                Add(name, version);\n                Resolve();\n            }\n            else\n            {\n                if (version.Equals(currentVersion))\n                {\n                    Debug.Log($\"This version of <color=Green>{name}</color> is installed\");\n                }\n                else\n                {\n                    Remove(name);\n                    Add(name, version);\n                    Resolve();\n                }\n            }\n        }\n\n        public static void Remove(string name)\n        {\n            var json = JObject.Parse(File.ReadAllText(ManifestPath));\n            var dependencies = (JObject)json[\"dependencies\"];\n            dependencies?.Remove(name);\n            Write(json);\n        }\n\n        public static (bool, string) IsInstalled(string name)\n        {\n            var json = JObject.Parse(File.ReadAllText(ManifestPath));\n            var dependencies = (JObject)json[\"dependencies\"];\n            if (dependencies != null)\n            {\n                foreach (var dependency in dependencies)\n                {\n                    if (dependency.Key.Equals(name)) return (true, dependency.Value.ToString());\n                }\n            }\n\n            return (false, \"\");\n        }\n\n        public static bool IsInstalledPackage(string name)\n        {\n            var json = JObject.Parse(File.ReadAllText(ManifestPath));\n            var dependencies = (JObject)json[\"dependencies\"];\n            if (dependencies != null)\n            {\n                foreach (var dependency in dependencies)\n                {\n                    if (dependency.Key.Equals(name)) return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static void Resolve()\n        {\n            Client.Resolve();\n        }\n\n        private static void Write(JObject json)\n        {\n            File.WriteAllText(ManifestPath, json.ToString());\n        }\n\n        public static (string, string) GetPackageInManifestByPackageName(string packageName)\n        {\n            string manifestContent = GetManifestContent();\n            if (manifestContent == null)\n            {\n                Debug.LogError(\"Could not find fileManifest.json\");\n                return (null, null);\n            }\n\n            JSONNode manifestJson = JSON.Parse(manifestContent);\n            JSONNode dependencies = manifestJson[\"dependencies\"];\n            if (dependencies != null && dependencies.Count > 0)\n            {\n                //  List<string> libraries = new List<string>();\n                foreach (KeyValuePair<string, JSONNode> dep in dependencies.AsObject)\n                {\n                    if (packageName == $\"\\\"{dep.Key}\\\"\")\n                    {\n                        // packageName and packageVersion\n                        return ($\"\\\"{dep.Key}\\\"\", $\": {dep.Value}\");\n                    }\n                    // libraries.Add($\"\\\"{dep.Key}\\\": {dep.Value}\");\n                }\n            }\n            else\n            {\n                Debug.LogError(\"Could not find dependencies or dependencies null.\");\n                return (null, null);\n            }\n\n            return (null, null);\n        }\n\n        public static void AddPackageInManifest(string packageFullName)\n        {\n            string manifestContent = GetManifestContent();\n            if (manifestContent != null)\n            {\n                int dependenciesIndex = manifestContent.IndexOf(\"\\\"dependencies\\\": {\") +\n                                        \"\\\"dependencies\\\": {\".Length;\n\n                manifestContent = manifestContent.Insert(dependenciesIndex,\n                    packageFullName);\n                WriteAllManifestContent(manifestContent);\n                Debug.Log($\"<color=Green>Add {packageFullName} to manifest</color>\");\n            }\n        }\n\n        public static void RemovePackageInManifest(string packageFullName)\n        {\n            string manifestContent = GetManifestContent();\n            if (manifestContent != null)\n            {\n                // int dependenciesIndex = manifestContent.IndexOf(\"\\\"dependencies\\\": {\") +\n                //                         \"\\\"dependencies\\\": {\".Length;\n\n                manifestContent = manifestContent.Replace(packageFullName,\n                    \"\");\n                WriteAllManifestContent(manifestContent);\n                Debug.Log($\"<color=Green>Remove {packageFullName} to manifest</color>\");\n            }\n        }\n\n        public static string GetManifestContent()\n        {\n            if (File.Exists(ManifestPath))\n            {\n                return File.ReadAllText(ManifestPath);\n            }\n\n            return null;\n        }\n\n        public static void WriteAllManifestContent(string manifestContent)\n        {\n            File.WriteAllText(ManifestPath, FileExtension.FormatJson(manifestContent));\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/RegistryManager.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c3b8339c355d4086a8413fc879e4b2cf\ntimeCreated: 1697173240"
  },
  {
    "path": "VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdef.txt",
    "content": "{\n    \"name\": \"virtuesky.purchasing.generate\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:94e1de2458b07d0bf1e9f13e6ae06443\",\n        \"GUID:d0bf1e9f644394e1de13e6ae02458b07\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdef.txt.meta",
    "content": "fileFormatVersion: 2\nguid: 46b89d27511c4a579d5b1a1ebe589cf9\ntimeCreated: 1697512999"
  },
  {
    "path": "VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdefMeta.txt",
    "content": "fileFormatVersion: 2\nguid: a90b00dc83a89964cb7641c304492d29\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/TemplateAssembly/PurchasingGeneratedAsmdefMeta.txt.meta",
    "content": "fileFormatVersion: 2\nguid: d9fc3d0a2c214d6b915bc32a042a9ab6\ntimeCreated: 1697513148"
  },
  {
    "path": "VirtueSky/Utils/Editor/TemplateAssembly.meta",
    "content": "fileFormatVersion: 2\nguid: 1d7799227ee44deba408233b2ddbe863\ntimeCreated: 1697512232"
  },
  {
    "path": "VirtueSky/Utils/Editor/TextureUtils.cs",
    "content": "﻿#if UNITY_EDITOR\n#endif\nusing System;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.UtilsEditor\n{\n#if UNITY_EDITOR\n    public static class TextureUtils\n    {\n        public static void CaptureToFile(Camera cam, string path, int width = 1024, int height = 1024, int depth = 24,\n            RenderTextureFormat format = RenderTextureFormat.ARGB32, TextureExtension extension = TextureExtension.PNG, bool refresh = true)\n        {\n            var rt = new RenderTexture(width, height, depth, format);\n            cam.targetTexture = rt;\n            cam.Render();\n\n            RenderTextureToFile(rt, path, extension, refresh);\n            cam.targetTexture = null;\n            Object.Destroy(rt);\n        }\n\n        public static void RenderTextureToFile(RenderTexture rt, string path, TextureExtension extension = TextureExtension.PNG, bool refresh = true)\n        {\n            var oldRt = RenderTexture.active;\n\n            var tex = new Texture2D(rt.width, rt.height);\n            RenderTexture.active = rt;\n            tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);\n            tex.Apply();\n\n            Texture2DToFile(tex, path, extension);\n\n            RenderTexture.active = oldRt;\n        }\n\n        public static void Texture2DToFile(Texture2D tex, string path, TextureExtension extension = TextureExtension.PNG, bool refresh = true)\n        {\n            switch (extension)\n            {\n                case TextureExtension.PNG:\n                    File.WriteAllBytes(path + \".png\", tex.EncodeToPNG());\n                    break;\n                case TextureExtension.JPG:\n                    File.WriteAllBytes(path + \".jpg\", tex.EncodeToJPG());\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException(nameof(extension), extension, null);\n            }\n\n\n            if (refresh)\n            {\n                AssetDatabase.Refresh();\n            }\n        }\n\n        public enum TextureExtension\n        {\n            PNG,\n            JPG\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/TextureUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 03a0e739fe864fc69e58652dc60f8e67\ntimeCreated: 1608451762"
  },
  {
    "path": "VirtueSky/Utils/Editor/Uniform.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEngine;\n\nnamespace VirtueSky.UtilsEditor\n{\n    public struct Uniform\n    {\n        #region field\n\n        private static GUIStyle contentList;\n        private static GUIStyle contentListBlue;\n        private static GUIStyle contentListDark;\n        private static GUIStyle contentBox;\n        private static GUIStyle box;\n        private static GUIStyle foldoutButton;\n        private static GUIStyle foldoutIcon;\n        private static GUIStyle installedIcon;\n        private static GUIStyle headerLabel;\n\n        private static readonly Dictionary<string, GUIContent> CachedIconContent =\n            new Dictionary<string, GUIContent>();\n\n        private static readonly UniformFoldoutState FoldoutSettings = new UniformFoldoutState();\n\n        #endregion\n\n\n        #region prop\n\n        public static GUIStyle ContentList\n        {\n            get\n            {\n                if (contentList != null) return contentList;\n                contentList = new GUIStyle\n                {\n                    border = new RectOffset(2, 2, 2, 2),\n                    normal = { background = EditorResources.EvenBackground }\n                };\n                return contentList;\n            }\n        }\n\n        public static GUIStyle ContentListBlue\n        {\n            get\n            {\n                if (contentListBlue != null) return contentListBlue;\n                contentListBlue = new GUIStyle\n                {\n                    border = new RectOffset(2, 2, 2, 2),\n                    normal = { background = EditorResources.EvenBackgroundBlue }\n                };\n                return contentListBlue;\n            }\n        }\n\n        public static GUIStyle ContentListDark\n        {\n            get\n            {\n                if (contentListDark != null) return contentListDark;\n                contentListDark = new GUIStyle\n                {\n                    border = new RectOffset(2, 2, 2, 2),\n                    normal = { background = EditorResources.EvenBackgroundDark }\n                };\n                return contentListDark;\n            }\n        }\n\n\n        public static GUIStyle BoxContent\n        {\n            get\n            {\n                if (contentBox != null) return contentBox;\n                contentBox = new GUIStyle\n                {\n                    border = new RectOffset(2, 2, 2, 2),\n                    normal =\n                    {\n                        background = EditorResources.BoxContentDark,\n                        scaledBackgrounds = new[] { EditorResources.BoxContentDark }\n                    }\n                };\n                return contentBox;\n            }\n        }\n\n        public static GUIStyle Box\n        {\n            get\n            {\n                if (box != null) return box;\n                box = new GUIStyle\n                {\n                    border = new RectOffset(2, 2, 2, 2),\n                    margin = new RectOffset(2, 2, 2, 2),\n                    normal =\n                    {\n                        background = EditorResources.BoxBackgroundDark,\n                        scaledBackgrounds = new[] { EditorResources.BoxBackgroundDark }\n                    }\n                };\n                return box;\n            }\n        }\n\n        public static GUIStyle FoldoutButton\n        {\n            get\n            {\n                if (foldoutButton != null) return foldoutButton;\n\n                foldoutButton = new GUIStyle\n                {\n                    normal = new GUIStyleState { textColor = Color.white },\n                    margin = new RectOffset(4, 4, 4, 4),\n                    padding = new RectOffset(0, 0, 2, 3),\n                    stretchWidth = true,\n                    richText = true,\n                    fontSize = 12,\n                    fontStyle = FontStyle.Bold\n                };\n\n                return foldoutButton;\n            }\n        }\n\n        public static GUIStyle FoldoutIcon\n        {\n            get\n            {\n                if (foldoutIcon != null) return foldoutIcon;\n\n                foldoutIcon = new GUIStyle { padding = new RectOffset(0, 0, 5, 0) };\n\n                return foldoutIcon;\n            }\n        }\n\n        public static GUIStyle InstalledIcon\n        {\n            get\n            {\n                if (installedIcon != null) return installedIcon;\n\n                installedIcon = new GUIStyle\n                    { padding = new RectOffset(0, 0, 3, 0), fixedWidth = 30, fixedHeight = 30 };\n\n                return installedIcon;\n            }\n        }\n\n        public static GUIStyle HeaderLabel\n        {\n            get\n            {\n                if (headerLabel != null) return headerLabel;\n                headerLabel = new GUIStyle(EditorStyles.label)\n                    { fontSize = 13, fontStyle = FontStyle.Bold };\n                return headerLabel;\n            }\n        }\n\n        #endregion\n\n\n        #region color\n\n        public static readonly Color Green = new(0.31f, 0.98f, 0.48f, 0.66f);\n        public static readonly Color Orange = new(1f, 0.72f, 0.42f, 0.66f);\n        public static readonly Color Blue = new(0f, 1f, 0.97f, 0.27f);\n        public static readonly Color Purple = new(0.74f, 0.58f, 0.98f, 0.39f);\n        public static readonly Color Red = new(1f, 0.16f, 0.16f, 0.66f);\n        public static readonly Color Pink = new(1f, 0.47f, 0.78f, 0.66f);\n        public static readonly Color RichBlack = new(0.04f, 0.05f, 0.11f);\n        public static readonly Color FieryRose = new(0.97f, 0.33f, 0.41f);\n        public static readonly Color DeepCarminePink = new(1f, 0.2f, 0.2f);\n        public static readonly Color FluorescentBlue = new(0.2f, 1f, 1f);\n\n        #endregion\n\n\n        #region draw\n\n        public static void DrawBox(Rect position, GUIStyle style, bool isHover = false,\n            bool isActive = false, bool on = false, bool hasKeyboardFocus = false)\n        {\n            if (Event.current.type == EventType.Repaint)\n            {\n                style.Draw(position,\n                    GUIContent.none,\n                    isHover,\n                    isActive,\n                    on,\n                    hasKeyboardFocus);\n            }\n        }\n\n        /// <summary>\n        /// Icon content\n        /// </summary>\n        /// <param name=\"name\"></param>\n        /// <param name=\"tooltip\"></param>\n        /// <returns></returns>\n        public static GUIContent IconContent(string name, string tooltip = \"\")\n        {\n            if (CachedIconContent.TryGetValue(name, out var result))\n                return result ?? GUIContent.none;\n            var builtinIcon = EditorGUIUtility.IconContent(name) ??\n                              new GUIContent(Texture2D.whiteTexture);\n            result = new GUIContent(builtinIcon.image, tooltip);\n            CachedIconContent.Add(name, result);\n            return result;\n        }\n\n        /// <summary>\n        /// Draw header with title\n        /// </summary>\n        /// <param name=\"title\"></param>\n        public static void DrawHeader(string title)\n        {\n            var bgStyle = new GUIStyle(GUIStyle.none)\n                { normal = { background = CreateTexture(RichBlack) } };\n            GUILayout.BeginVertical(bgStyle, GUILayout.Height(60));\n            GUILayout.BeginHorizontal();\n\n            var iconStyle = new GUIStyle(GUIStyle.none) { padding = new RectOffset(2, 0, 2, 2) };\n            // GUILayout.Box(EditorResources.Dreamblale, iconStyle, GUILayout.Width(60), GUILayout.Height(60));\n\n            var titleStyle = new GUIStyle(GUIStyle.none)\n            {\n                margin = new RectOffset(4, 4, 4, 4),\n                fontSize = 20,\n                fontStyle = FontStyle.Bold,\n                alignment = TextAnchor.MiddleLeft,\n                wordWrap = false,\n                richText = true,\n                imagePosition = ImagePosition.ImageLeft,\n                fixedHeight = 50,\n                stretchHeight = true,\n                stretchWidth = true,\n                normal = { textColor = Color.white }\n            };\n\n            EditorGUILayout.LabelField(title, titleStyle);\n            GUILayout.FlexibleSpace();\n            GUILayout.EndHorizontal();\n            GUILayout.EndVertical();\n        }\n\n\n        // public static Texture2D Dreamblale => ProjectDatabase.FindAssetWithPath<Texture2D>(\"dreamblade.png\", RELATIVE_PATH);\n\n        public static Texture2D CreateTexture(Color color)\n        {\n            var result = new Texture2D(1, 1, TextureFormat.RGBA32, false);\n            result.SetPixel(0, 0, color);\n            result.Apply();\n            return result;\n        }\n\n        /// <summary>\n        /// Draw only the property specified.\n        /// </summary>\n        /// <param name=\"serializedObject\"></param>\n        /// <param name=\"fieldName\"></param>\n        /// <param name=\"isReadOnly\"></param>\n        public static void DrawOnlyField(SerializedObject serializedObject, string fieldName,\n            bool isReadOnly)\n        {\n            serializedObject.Update();\n            var prop = serializedObject.GetIterator();\n            if (prop.NextVisible(true))\n            {\n                do\n                {\n                    if (prop.name != fieldName) continue;\n\n                    GUI.enabled = !isReadOnly;\n                    EditorGUILayout.PropertyField(serializedObject.FindProperty(prop.name), true);\n                    GUI.enabled = true;\n                } while (prop.NextVisible(false));\n            }\n\n            serializedObject.ApplyModifiedProperties();\n        }\n\n        /// <summary>\n        /// Draws a line in the inspector.\n        /// </summary>\n        /// <param name=\"height\"></param>\n        public static void DrawLine(int height = 1)\n        {\n            var rect = EditorGUILayout.GetControlRect(false, height);\n            rect.height = height;\n            EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 1));\n        }\n\n        /// <summary>\n        /// Draw a selectable object\n        /// </summary>\n        /// <param name=\"obj\"></param>\n        /// <param name=\"labels\"></param>\n        public static void DrawSelectableObject(Object obj, string[] labels)\n        {\n            GUILayout.BeginHorizontal();\n            GUILayout.FlexibleSpace();\n            if (GUILayout.Button(labels[0], GUILayout.MaxWidth(300)))\n                EditorGUIUtility.PingObject(obj);\n\n            if (GUILayout.Button(labels[1], GUILayout.MaxWidth(75)))\n            {\n                EditorWindow.FocusWindowIfItsOpen(typeof(SceneView));\n                Selection.activeObject = obj;\n                SceneView.FrameLastActiveSceneView();\n            }\n\n            GUILayout.FlexibleSpace();\n            GUILayout.EndHorizontal();\n            GUILayout.Space(2);\n        }\n\n        /// <summary>\n        /// Draws all properties like base.OnInspectorGUI() but excludes a field by name.\n        /// </summary>\n        /// <param name=\"serializedObject\"></param>\n        /// <param name=\"fieldToSkip\">The name of the field that should be excluded. Example: \"m_Script\" will skip the default Script field.</param>\n        public static void DrawInspectorExcept(SerializedObject serializedObject,\n            string fieldToSkip)\n        {\n            Uniform.DrawInspectorExcept(serializedObject, new[] { fieldToSkip });\n        }\n\n        /// <summary>\n        /// Draws all properties like base.OnInspectorGUI() but excludes the specified fields by name.\n        /// </summary>\n        /// <param name=\"serializedObject\"></param>\n        /// <param name=\"fieldsToSkip\">\n        /// An array of names that should be excluded.\n        /// Example: new string[] { \"m_Script\" , \"myInt\" } will skip the default Script field and the Integer field myInt.\n        /// </param>\n        public static void DrawInspectorExcept(SerializedObject serializedObject,\n            string[] fieldsToSkip)\n        {\n            serializedObject.Update();\n            var prop = serializedObject.GetIterator();\n            if (prop.NextVisible(true))\n            {\n                do\n                {\n                    if (fieldsToSkip.Any(prop.name.Contains)) continue;\n\n                    EditorGUILayout.PropertyField(serializedObject.FindProperty(prop.name), true);\n                } while (prop.NextVisible(false));\n            }\n\n            serializedObject.ApplyModifiedProperties();\n        }\n\n        /// <summary>\n        /// Draw group selection with header\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <param name=\"sectionName\"></param>\n        /// <param name=\"drawer\"></param>\n        /// <param name=\"defaultFoldout\"></param>\n        /// <param name=\"isShowContent\"></param>\n        public static float DrawGroupFoldout(string key, string sectionName, System.Action drawer,\n            bool defaultFoldout = true, bool isShowContent = true)\n        {\n            bool foldout = GetFoldoutState(key, defaultFoldout);\n\n            var rect = EditorGUILayout.BeginVertical(Box,\n                GUILayout.MinHeight(foldout && isShowContent ? 30 : 0));\n\n            if (!isShowContent)\n            {\n                EditorGUILayout.LabelField(sectionName);\n            }\n            else\n            {\n                EditorGUILayout.BeginHorizontal();\n\n                // Header label (and button).\n                if (GUILayout.Button($\"    {sectionName}\", FoldoutButton))\n                    SetFoldoutState(key, !foldout);\n\n                // The expand/collapse icon.\n                var buttonRect = GUILayoutUtility.GetLastRect();\n                var iconRect = new Rect(buttonRect.x, buttonRect.y, 10, buttonRect.height);\n                GUI.Label(iconRect,\n                    foldout ? IconContent(\"d_IN_foldout_act_on\") : IconContent(\"d_IN_foldout\"),\n                    FoldoutIcon);\n\n                EditorGUILayout.EndHorizontal();\n\n                // Draw the section content.\n                if (foldout) GUILayout.Space(5);\n                if (foldout && drawer != null) drawer();\n            }\n\n            float height = rect.height;\n            EditorGUILayout.EndVertical();\n            height += 4;\n            return height;\n        }\n\n        /// <summary>\n        /// Draw group selection with header\n        /// </summary>\n        /// <param name=\"key\"></param>\n        /// <param name=\"sectionName\"></param>\n        /// <param name=\"drawer\"></param>\n        /// <param name=\"actionRightClick\"></param>\n        /// <param name=\"defaultFoldout\"></param>\n        /// <param name=\"isShowContent\"></param>\n        public static float DrawGroupFoldoutWithRightClick(\n            string key,\n            string sectionName,\n            System.Action drawer,\n            System.Action actionRightClick,\n            bool defaultFoldout = true,\n            bool isShowContent = true)\n        {\n            bool foldout = GetFoldoutState(key, defaultFoldout);\n\n            var rect = EditorGUILayout.BeginVertical(Box,\n                GUILayout.MinHeight(foldout && isShowContent ? 30 : 0));\n\n            if (!isShowContent)\n            {\n                EditorGUILayout.LabelField(sectionName);\n            }\n            else\n            {\n                EditorGUILayout.BeginHorizontal();\n\n                // Header label (and button).\n                if (GUILayout.Button($\"    {sectionName}\", FoldoutButton))\n                {\n                    if (Event.current.button == 1)\n                    {\n                        actionRightClick?.Invoke();\n                        return rect.height;\n                    }\n\n                    SetFoldoutState(key, !foldout);\n                }\n\n                // The expand/collapse icon.\n                var buttonRect = GUILayoutUtility.GetLastRect();\n                var iconRect = new Rect(buttonRect.x, buttonRect.y, 10, buttonRect.height);\n                GUI.Label(iconRect,\n                    foldout ? IconContent(\"d_IN_foldout_act_on\") : IconContent(\"d_IN_foldout\"),\n                    FoldoutIcon);\n\n                EditorGUILayout.EndHorizontal();\n\n                // Draw the section content.\n                if (foldout) GUILayout.Space(5);\n                if (foldout && drawer != null) drawer();\n            }\n\n            float height = rect.height;\n            EditorGUILayout.EndVertical();\n            height += 4;\n            return height;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"fieldTitle\"></param>\n        /// <param name=\"text\"></param>\n        /// <param name=\"labelWidth\"></param>\n        /// <param name=\"textFieldWidthOption\"></param>\n        /// <returns></returns>\n        public static string DrawTextField(string fieldTitle, string text,\n            GUILayoutOption labelWidth, GUILayoutOption textFieldWidthOption = null)\n        {\n            GUILayout.BeginHorizontal();\n            GUILayout.Space(4);\n            EditorGUILayout.LabelField(new GUIContent(fieldTitle), labelWidth);\n            GUILayout.Space(4);\n            text = textFieldWidthOption == null\n                ? GUILayout.TextField(text)\n                : GUILayout.TextField(text, textFieldWidthOption);\n            GUILayout.Space(4);\n            GUILayout.EndHorizontal();\n            GUILayout.Space(4);\n\n            return text;\n        }\n\n        /// <summary>\n        /// Centers a rect inside another window.\n        /// </summary>\n        /// <param name=\"window\"></param>\n        /// <param name=\"origin\"></param>\n        /// <returns></returns>\n        public static Rect CenterInWindow(Rect window, Rect origin)\n        {\n            var pos = window;\n            float w = (origin.width - pos.width) * 0.5f;\n            float h = (origin.height - pos.height) * 0.5f;\n            pos.x = origin.x + w;\n            pos.y = origin.y + h;\n            return pos;\n        }\n\n        /// <summary>\n        /// Draw label installed and icon\n        /// </summary>\n        public static void DrawInstalled(string version)\n        {\n            EditorGUILayout.BeginHorizontal();\n            var label = $\"Installed {version}\";\n            GUILayout.Label(label);\n            var lastRect = GUILayoutUtility.GetLastRect();\n            var iconRect = new Rect(lastRect.x + label.Length * 6f, lastRect.y, 10,\n                lastRect.height);\n            GUI.Label(iconRect, Uniform.IconContent(\"CollabNew\"), InstalledIcon);\n            EditorGUILayout.EndHorizontal();\n        }\n\n        #endregion\n\n\n        #region foldout state\n\n        public static bool GetFoldoutState(string key, bool defaultFoldout = true)\n        {\n            if (!FoldoutSettings.ContainsKey(key)) FoldoutSettings.Add(key, defaultFoldout);\n            return FoldoutSettings[key];\n        }\n\n        public static void SetFoldoutState(string key, bool state)\n        {\n            if (!FoldoutSettings.ContainsKey(key))\n            {\n                FoldoutSettings.Add(key, state);\n            }\n            else\n            {\n                FoldoutSettings[key] = state;\n            }\n        }\n\n        [System.Serializable]\n        public class FoldoutState\n        {\n            public string key;\n            public bool state;\n        }\n\n        [System.Serializable]\n        public class UniformFoldoutState\n        {\n            public List<FoldoutState> uniformFoldouts;\n\n            public UniformFoldoutState()\n            {\n                uniformFoldouts = new List<FoldoutState>();\n            }\n\n            public bool ContainsKey(string key)\n            {\n                return uniformFoldouts.Any(foldoutState => foldoutState.key.Equals(key));\n            }\n\n            public void Add(string key, bool value)\n            {\n                uniformFoldouts.Add(new FoldoutState { key = key, state = value });\n            }\n\n            public bool this[string key]\n            {\n                get\n                {\n                    foreach (var foldoutState in uniformFoldouts)\n                    {\n                        if (foldoutState.key.Equals(key))\n                        {\n                            return foldoutState.state;\n                        }\n                    }\n\n                    return false;\n                }\n                set\n                {\n                    foreach (var foldoutState in uniformFoldouts)\n                    {\n                        if (foldoutState.key.Equals(key))\n                        {\n                            foldoutState.state = value;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/Uniform.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9f0e29e6ef9d4f7fa00db23754c9ee67\ntimeCreated: 1697168886"
  },
  {
    "path": "VirtueSky/Utils/Editor/UnityPackage/Note_Package.txt",
    "content": "- Version Max Sdk: 8.6.2\n- Version Google Game Play Service: v2.1.0"
  },
  {
    "path": "VirtueSky/Utils/Editor/UnityPackage/Note_Package.txt.meta",
    "content": "fileFormatVersion: 2\nguid: 0acfd990870be8348a3ea75a1ef44ffa\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/UnityPackage/google-play-game.unitypackage.meta",
    "content": "fileFormatVersion: 2\nguid: 2008ec393deb9b14697035729927bc9c\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/UnityPackage/max-sdk.unitypackage.meta",
    "content": "fileFormatVersion: 2\nguid: 53509e528178d1d4891a421c469c5c6e\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/UnityPackage.meta",
    "content": "fileFormatVersion: 2\nguid: 7f0ec4ddaa968214bb0e3a8413730912\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor/Virtuesky.Sunflower.UtilsEdtitor.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.UtilsEdtitor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:98c7400721ddc874d9bad4ee2f3f66d6\",\n        \"GUID:efdee36e63e4ce34a91071531ec746c1\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Utils/Editor/Virtuesky.Sunflower.UtilsEdtitor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: c904f6d969e991d459a0843b71c22ec5\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 3deb402fc5e746f8a228f15e52329ed1\ntimeCreated: 1699932105"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ColorExtensions.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.Utils\n{\n    public static class ColorExtensions\n    {\n        // Convert the TitleColor enum to an actual Color32\n        public static Color32 ToColor(this CustomColor color)\n        {\n            switch (color)\n            {\n                case CustomColor.AliceBlue: return new Color32(240, 248, 255, 255);\n                case CustomColor.AntiqueWhite: return new Color32(250, 235, 215, 255);\n                case CustomColor.Aqua: return new Color32(0, 255, 255, 255);\n                case CustomColor.Aquamarine: return new Color32(127, 255, 212, 255);\n                case CustomColor.Azure: return new Color32(240, 255, 255, 255);\n                case CustomColor.Beige: return new Color32(245, 245, 220, 255);\n                case CustomColor.Bisque: return new Color32(255, 228, 196, 255);\n                case CustomColor.Black: return new Color32(0, 0, 0, 255);\n                case CustomColor.BlanchedAlmond: return new Color32(255, 235, 205, 255);\n                case CustomColor.Blue: return new Color32(0, 0, 255, 255);\n                case CustomColor.BlueViolet: return new Color32(138, 43, 226, 255);\n                case CustomColor.Brown: return new Color32(165, 42, 42, 255);\n                case CustomColor.Burlywood: return new Color32(222, 184, 135, 255);\n                case CustomColor.CadetBlue: return new Color32(95, 158, 160, 255);\n                case CustomColor.Chartreuse: return new Color32(127, 255, 0, 255);\n                case CustomColor.Chocolate: return new Color32(210, 105, 30, 255);\n                case CustomColor.Coral: return new Color32(255, 127, 80, 255);\n                case CustomColor.CornflowerBlue: return new Color32(100, 149, 237, 255);\n                case CustomColor.Cornsilk: return new Color32(255, 248, 220, 255);\n                case CustomColor.Crimson: return new Color32(220, 20, 60, 255);\n                case CustomColor.Cyan: return new Color32(0, 255, 255, 255);\n                case CustomColor.DarkBlue: return new Color32(0, 0, 139, 255);\n                case CustomColor.DarkCyan: return new Color32(0, 139, 139, 255);\n                case CustomColor.DarkGoldenrod: return new Color32(184, 134, 11, 255);\n                case CustomColor.DarkGray: return new Color32(169, 169, 169, 255);\n                case CustomColor.DarkGreen: return new Color32(0, 100, 0, 255);\n                case CustomColor.DarkKhaki: return new Color32(189, 183, 107, 255);\n                case CustomColor.DarkMagenta: return new Color32(139, 0, 139, 255);\n                case CustomColor.DarkOliveGreen: return new Color32(85, 107, 47, 255);\n                case CustomColor.DarkOrange: return new Color32(255, 140, 0, 255);\n                case CustomColor.DarkOrchid: return new Color32(153, 50, 204, 255);\n                case CustomColor.DarkRed: return new Color32(139, 0, 0, 255);\n                case CustomColor.DarkSalmon: return new Color32(233, 150, 122, 255);\n                case CustomColor.DarkSeaGreen: return new Color32(143, 188, 143, 255);\n                case CustomColor.DarkSlateBlue: return new Color32(72, 61, 139, 255);\n                case CustomColor.DarkSlateGray: return new Color32(47, 79, 79, 255);\n                case CustomColor.DarkTurquoise: return new Color32(0, 206, 209, 255);\n                case CustomColor.DarkViolet: return new Color32(148, 0, 211, 255);\n                case CustomColor.DeepPink: return new Color32(255, 20, 147, 255);\n                case CustomColor.DeepSkyBlue: return new Color32(0, 191, 255, 255);\n                case CustomColor.DimGray: return new Color32(105, 105, 105, 255);\n                case CustomColor.DodgerBlue: return new Color32(30, 144, 255, 255);\n                case CustomColor.FireBrick: return new Color32(178, 34, 34, 255);\n                case CustomColor.FloralWhite: return new Color32(255, 250, 240, 255);\n                case CustomColor.ForestGreen: return new Color32(34, 139, 34, 255);\n                case CustomColor.Fuchsia: return new Color32(255, 0, 255, 255);\n                case CustomColor.Gainsboro: return new Color32(220, 220, 220, 255);\n                case CustomColor.GhostWhite: return new Color32(248, 248, 255, 255);\n                case CustomColor.Gold: return new Color32(255, 215, 0, 255);\n                case CustomColor.Goldenrod: return new Color32(218, 165, 32, 255);\n                case CustomColor.Gray: return new Color32(128, 128, 128, 255);\n                case CustomColor.Green: return new Color32(0, 128, 0, 255);\n                case CustomColor.GreenYellow: return new Color32(173, 255, 47, 255);\n                case CustomColor.Honeydew: return new Color32(240, 255, 240, 255);\n                case CustomColor.HotPink: return new Color32(255, 105, 180, 255);\n                case CustomColor.IndianRed: return new Color32(205, 92, 92, 255);\n                case CustomColor.Indigo: return new Color32(75, 0, 130, 255);\n                case CustomColor.Ivory: return new Color32(255, 255, 240, 255);\n                case CustomColor.Khaki: return new Color32(240, 230, 140, 255);\n                case CustomColor.Lavender: return new Color32(230, 230, 250, 255);\n                case CustomColor.Lavenderblush: return new Color32(255, 240, 245, 255);\n                case CustomColor.LawnGreen: return new Color32(124, 252, 0, 255);\n                case CustomColor.LemonChiffon: return new Color32(255, 250, 205, 255);\n                case CustomColor.LightBlue: return new Color32(173, 216, 230, 255);\n                case CustomColor.LightCoral: return new Color32(240, 128, 128, 255);\n                case CustomColor.LightCyan: return new Color32(224, 255, 255, 255);\n                case CustomColor.LightGoldenodYellow: return new Color32(250, 250, 210, 255);\n                case CustomColor.LightGray: return new Color32(211, 211, 211, 255);\n                case CustomColor.LightGreen: return new Color32(144, 238, 144, 255);\n                case CustomColor.LightPink: return new Color32(255, 182, 193, 255);\n                case CustomColor.LightSalmon: return new Color32(255, 160, 122, 255);\n                case CustomColor.LightSeaGreen: return new Color32(32, 178, 170, 255);\n                case CustomColor.LightSkyBlue: return new Color32(135, 206, 250, 255);\n                case CustomColor.LightSlateGray: return new Color32(119, 136, 153, 255);\n                case CustomColor.LightSteelBlue: return new Color32(176, 196, 222, 255);\n                case CustomColor.LightYellow: return new Color32(255, 255, 224, 255);\n                case CustomColor.Lime: return new Color32(0, 255, 0, 255);\n                case CustomColor.LimeGreen: return new Color32(50, 205, 50, 255);\n                case CustomColor.Linen: return new Color32(250, 240, 230, 255);\n                case CustomColor.Magenta: return new Color32(255, 0, 255, 255);\n                case CustomColor.Maroon: return new Color32(128, 0, 0, 255);\n                case CustomColor.MediumAquamarine: return new Color32(102, 205, 170, 255);\n                case CustomColor.MediumBlue: return new Color32(0, 0, 205, 255);\n                case CustomColor.MediumOrchid: return new Color32(186, 85, 211, 255);\n                case CustomColor.MediumPurple: return new Color32(147, 112, 219, 255);\n                case CustomColor.MediumSeaGreen: return new Color32(60, 179, 113, 255);\n                case CustomColor.MediumSlateBlue: return new Color32(123, 104, 238, 255);\n                case CustomColor.MediumSpringGreen: return new Color32(0, 250, 154, 255);\n                case CustomColor.MediumTurquoise: return new Color32(72, 209, 204, 255);\n                case CustomColor.MediumVioletRed: return new Color32(199, 21, 133, 255);\n                case CustomColor.MidnightBlue: return new Color32(25, 25, 112, 255);\n                case CustomColor.Mintcream: return new Color32(245, 255, 250, 255);\n                case CustomColor.MistyRose: return new Color32(255, 228, 225, 255);\n                case CustomColor.Moccasin: return new Color32(255, 228, 181, 255);\n                case CustomColor.NavajoWhite: return new Color32(255, 222, 173, 255);\n                case CustomColor.Navy: return new Color32(0, 0, 128, 255);\n                case CustomColor.OldLace: return new Color32(253, 245, 230, 255);\n                case CustomColor.Olive: return new Color32(128, 128, 0, 255);\n                case CustomColor.Olivedrab: return new Color32(107, 142, 35, 255);\n                case CustomColor.Orange: return new Color32(255, 165, 0, 255);\n                case CustomColor.Orangered: return new Color32(255, 69, 0, 255);\n                case CustomColor.Orchid: return new Color32(218, 112, 214, 255);\n                case CustomColor.PaleGoldenrod: return new Color32(238, 232, 170, 255);\n                case CustomColor.PaleGreen: return new Color32(152, 251, 152, 255);\n                case CustomColor.PaleTurquoise: return new Color32(175, 238, 238, 255);\n                case CustomColor.PaleVioletred: return new Color32(219, 112, 147, 255);\n                case CustomColor.PapayaWhip: return new Color32(255, 239, 213, 255);\n                case CustomColor.PeachPuff: return new Color32(255, 218, 185, 255);\n                case CustomColor.Peru: return new Color32(205, 133, 63, 255);\n                case CustomColor.Pink: return new Color32(255, 192, 203, 255);\n                case CustomColor.Plum: return new Color32(221, 160, 221, 255);\n                case CustomColor.PowderBlue: return new Color32(176, 224, 230, 255);\n                case CustomColor.Purple: return new Color32(128, 0, 128, 255);\n                case CustomColor.Red: return new Color32(255, 0, 0, 255);\n                case CustomColor.RosyBrown: return new Color32(188, 143, 143, 255);\n                case CustomColor.RoyalBlue: return new Color32(65, 105, 225, 255);\n                case CustomColor.SaddleBrown: return new Color32(139, 69, 19, 255);\n                case CustomColor.Salmon: return new Color32(250, 128, 114, 255);\n                case CustomColor.SandyBrown: return new Color32(244, 164, 96, 255);\n                case CustomColor.SeaGreen: return new Color32(46, 139, 87, 255);\n                case CustomColor.Seashell: return new Color32(255, 245, 238, 255);\n                case CustomColor.Sienna: return new Color32(160, 82, 45, 255);\n                case CustomColor.Silver: return new Color32(192, 192, 192, 255);\n                case CustomColor.SkyBlue: return new Color32(135, 206, 235, 255);\n                case CustomColor.SlateBlue: return new Color32(106, 90, 205, 255);\n                case CustomColor.SlateGray: return new Color32(112, 128, 144, 255);\n                case CustomColor.Snow: return new Color32(255, 250, 250, 255);\n                case CustomColor.SpringGreen: return new Color32(0, 255, 127, 255);\n                case CustomColor.SteelBlue: return new Color32(70, 130, 180, 255);\n                case CustomColor.Tan: return new Color32(210, 180, 140, 255);\n                case CustomColor.Teal: return new Color32(0, 128, 128, 255);\n                case CustomColor.Thistle: return new Color32(216, 191, 216, 255);\n                case CustomColor.Tomato: return new Color32(255, 99, 71, 255);\n                case CustomColor.Turquoise: return new Color32(64, 224, 208, 255);\n                case CustomColor.Violet: return new Color32(238, 130, 238, 255);\n                case CustomColor.Wheat: return new Color32(245, 222, 179, 255);\n                case CustomColor.White: return new Color32(255, 255, 255, 255);\n                case CustomColor.WhiteSmoke: return new Color32(245, 245, 245, 255);\n                case CustomColor.Yellow: return new Color32(255, 255, 0, 255);\n                case CustomColor.YellowGreen: return new Color32(154, 205, 50, 255);\n                case CustomColor.BlueVariant: return new Color32(67, 110, 238, 255);\n                case CustomColor.Bright: return new Color32(196, 196, 196, 255);\n                case CustomColor.DarkOlive: return new Color32(47, 79, 79, 255);\n                case CustomColor.OrangeVariant: return new Color32(255, 135, 62, 255);\n                case CustomColor.LightRed: return new Color32(217, 71, 71, 255);\n                case CustomColor.RedVariant: return new Color32(232, 10, 10, 255);\n                default: return new Color32(0, 0, 0, 0);\n            }\n        }\n    }\n\n    public enum CustomColor\n    {\n        AliceBlue,\n        AntiqueWhite,\n        Aqua,\n        Aquamarine,\n        Azure,\n        Beige,\n        Bisque,\n        Black,\n        BlanchedAlmond,\n        Blue,\n        BlueViolet,\n        BlueVariant,\n        Brown,\n        Burlywood,\n        Bright,\n        CadetBlue,\n        Chartreuse,\n        Chocolate,\n        Coral,\n        CornflowerBlue,\n        Cornsilk,\n        Crimson,\n        Cyan,\n        DarkBlue,\n        DarkCyan,\n        DarkGoldenrod,\n        DarkGray,\n        DarkGreen,\n        DarkKhaki,\n        DarkMagenta,\n        DarkOlive,\n        DarkOliveGreen,\n        DarkOrange,\n        DarkOrchid,\n        DarkRed,\n        DarkSalmon,\n        DarkSeaGreen,\n        DarkSlateBlue,\n        DarkSlateGray,\n        DarkTurquoise,\n        DarkViolet,\n        DeepPink,\n        DeepSkyBlue,\n        DimGray,\n        DodgerBlue,\n        FireBrick,\n        FloralWhite,\n        ForestGreen,\n        Fuchsia,\n        Gainsboro,\n        GhostWhite,\n        Gold,\n        Goldenrod,\n        Gray,\n        Green,\n        GreenYellow,\n        Honeydew,\n        HotPink,\n        IndianRed,\n        Indigo,\n        Ivory,\n        Khaki,\n        Lavender,\n        Lavenderblush,\n        LawnGreen,\n        LemonChiffon,\n        LightBlue,\n        LightCoral,\n        LightCyan,\n        LightGoldenodYellow,\n        LightGray,\n        LightGreen,\n        LightPink,\n        LightRed,\n        LightSalmon,\n        LightSeaGreen,\n        LightSkyBlue,\n        LightSlateGray,\n        LightSteelBlue,\n        LightYellow,\n        Lime,\n        LimeGreen,\n        Linen,\n        Magenta,\n        Maroon,\n        MediumAquamarine,\n        MediumBlue,\n        MediumOrchid,\n        MediumPurple,\n        MediumSeaGreen,\n        MediumSlateBlue,\n        MediumSpringGreen,\n        MediumTurquoise,\n        MediumVioletRed,\n        MidnightBlue,\n        Mintcream,\n        MistyRose,\n        Moccasin,\n        NavajoWhite,\n        Navy,\n        OldLace,\n        Olive,\n        Olivedrab,\n        Orange,\n        Orangered,\n        OrangeVariant,\n        Orchid,\n        PaleGoldenrod,\n        PaleGreen,\n        PaleTurquoise,\n        PaleVioletred,\n        PapayaWhip,\n        PeachPuff,\n        Peru,\n        Pink,\n        Plum,\n        PowderBlue,\n        Purple,\n        Red,\n        RedVariant,\n        RosyBrown,\n        RoyalBlue,\n        SaddleBrown,\n        Salmon,\n        SandyBrown,\n        SeaGreen,\n        Seashell,\n        Sienna,\n        Silver,\n        SkyBlue,\n        SlateBlue,\n        SlateGray,\n        Snow,\n        SpringGreen,\n        SteelBlue,\n        Tan,\n        Teal,\n        Thistle,\n        Tomato,\n        Turquoise,\n        Violet,\n        Wheat,\n        White,\n        WhiteSmoke,\n        Yellow,\n        YellowGreen,\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ColorExtensions.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 8eaf9fcfd2284c44971d398f8fc71851\ntimeCreated: 1700209802"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ExtensionUtils.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.AI;\nusing UnityEngine.Networking;\n\nnamespace VirtueSky.Utils\n{\n    public static class MonoBehaviorExtension\n    {\n        public static Coroutine Delay(this MonoBehaviour mono, float time, bool realTime, System.Action callback)\n        {\n            return mono.StartCoroutine(WaitForExtraTime(time, realTime, callback));\n        }\n\n        static IEnumerator WaitForExtraTime(float time, bool realTime, System.Action callback)\n        {\n            if (realTime)\n            {\n                yield return new WaitForSecondsRealtime(time);\n            }\n            else\n            {\n                yield return new WaitForSeconds(time);\n            }\n\n            callback?.Invoke();\n        }\n\n        public static Coroutine Delay(this MonoBehaviour mono, int frame, System.Action callback)\n        {\n            return mono.StartCoroutine(WaitForExtraFrame(frame, callback));\n        }\n\n        static IEnumerator WaitForExtraFrame(int frame, System.Action callback)\n        {\n            for (var i = 0; i < frame; i++)\n            {\n                yield return null;\n            }\n\n            callback?.Invoke();\n        }\n\n        public static Coroutine WaitUntil(this MonoBehaviour mono, Func<bool> condition, Action callback)\n        {\n            return mono.StartCoroutine(WaitUntil(condition, callback));\n        }\n\n        static IEnumerator WaitUntil(Func<bool> condition, Action callback)\n        {\n            yield return new WaitUntil(condition);\n            callback?.Invoke();\n        }\n\n        public static T GetAndCacheComponent<T>(this MonoBehaviour mono, ref T cache) where T : Component\n        {\n            return cache ? cache : (cache = mono.GetComponent<T>());\n        }\n\n        public static T GetAndCacheComponentInChildren<T>(this MonoBehaviour mono, ref T cache, bool includeInactive = false)\n        {\n            return cache ??= mono.GetComponentInChildren<T>(includeInactive);\n        }\n\n        public static T[] GetAndCacheComponents<T>(this MonoBehaviour mono, ref T[] cache) where T : Component\n        {\n            return cache ??= mono.GetComponents<T>();\n        }\n\n        public static T[] GetAndCacheComponentsInChildren<T>(this MonoBehaviour mono, ref T[] cache, bool includeInactive = false)\n        {\n            return cache ??= mono.GetComponentsInChildren<T>(includeInactive);\n        }\n\n        public static T GetAndCacheComponentInParent<T>(this MonoBehaviour mono, ref T cache)\n        {\n            return cache ??= mono.GetComponentInParent<T>();\n        }\n    }\n\n    public static class GameObjectExtension\n    {\n        static List<Component> m_ComponentCache = new List<Component>();\n\n        public static Component GetComponentNoAlloc(this GameObject go, System.Type componentType)\n        {\n            go.GetComponents(componentType, m_ComponentCache);\n            var component = m_ComponentCache.Count > 0 ? m_ComponentCache[0] : null;\n            m_ComponentCache.Clear();\n            return component;\n        }\n\n        public static T GetComponentNoAlloc<T>(this GameObject go) where T : Component\n        {\n            go.GetComponents(typeof(T), m_ComponentCache);\n            var component = m_ComponentCache.Count > 0 ? m_ComponentCache[0] : null;\n            m_ComponentCache.Clear();\n            return component as T;\n        }\n\n        public static T GetAndCacheComponent<T>(this GameObject go, ref T cache)\n        {\n            return cache ??= go.GetComponent<T>();\n        }\n\n        public static T GetAndCacheComponentInChildren<T>(this GameObject go, bool includeInactive, ref T cache)\n        {\n            return cache ??= go.GetComponentInChildren<T>(includeInactive);\n        }\n    }\n\n    public static class TransformExtensions\n    {\n        public static void RandomRotation(this Transform transform, bool onlyY = false)\n        {\n            transform.rotation = SimpleMath.RandomRotation(onlyY);\n        }\n\n        public static void RandomLocalRotation(this Transform transform, bool onlyY = false)\n        {\n            transform.localRotation = SimpleMath.RandomRotation(onlyY);\n        }\n\n        public static void Copy(this Transform transform, Transform other, bool position, bool rotation, bool scale, bool otherLossyScale)\n        {\n            if (position) transform.position = other.transform.position;\n            if (rotation) transform.rotation = other.transform.rotation;\n            if (scale)\n            {\n                transform.localScale = otherLossyScale ? other.transform.lossyScale : other.transform.localScale;\n            }\n        }\n\n        public static void ResetLocal(this Transform transform)\n        {\n            transform.localPosition = Vector3.zero;\n            transform.localRotation = Quaternion.identity;\n        }\n\n        // public static Tween DORotateQuaternionXZ(this Transform transform, Vector3 pos, float duration)\n        // {\n        //     var dir = pos - transform.position;\n        //     dir.y = 0;\n        //     return transform.DORotateQuaternion(Quaternion.LookRotation(dir), duration);\n        // }\n\n        public static Vector2 position2D(this Transform transform)\n        {\n            return transform.position;\n        }\n\n        public static Vector2 localPosition2D(this Transform transform)\n        {\n            return transform.localPosition;\n        }\n\n        public static Bounds GetBounds(this Transform transform)\n        {\n            var bound = new Bounds();\n            var renderers = transform.GetComponentsInChildren<Renderer>().Where(r => !(r is ParticleSystemRenderer)).ToArray();\n\n            for (var j = 0; j < renderers.Length; j++)\n            {\n                if (j == 0) bound = renderers[j].bounds;\n                else bound.Encapsulate(renderers[j].bounds);\n            }\n\n            return bound;\n        }\n\n#if UNITY_EDITOR\n        [MenuItem(\"CONTEXT/Transform/ExpandX\")]\n        public static void ExpandX(MenuCommand command)\n        {\n            var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.x).ToArray();\n            if (tfs.Length > 2)\n            {\n                Undo.RecordObjects(tfs, \"ExpandX\");\n                var min = tfs[0].position.x;\n                var max = tfs[tfs.Length - 1].position.x;\n                var step = (max - min) / (tfs.Length - 1);\n                for (var i = 0; i < tfs.Length; i++)\n                {\n                    var pos = tfs[i].position;\n                    pos.x = min + step * i;\n                    tfs[i].position = pos;\n                    EditorUtility.SetDirty(tfs[i]);\n                }\n            }\n        }\n\n        [MenuItem(\"CONTEXT/Transform/ExpandY\")]\n        public static void ExpandY(MenuCommand command)\n        {\n            var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.y).ToArray();\n            if (tfs.Length > 2)\n            {\n                Undo.RecordObjects(tfs, \"ExpandY\");\n                var min = tfs[0].position.y;\n                var max = tfs[tfs.Length - 1].position.y;\n                var step = (max - min) / (tfs.Length - 1);\n                for (var i = 0; i < tfs.Length; i++)\n                {\n                    var pos = tfs[i].position;\n                    pos.y = min + step * i;\n                    tfs[i].position = pos;\n                    EditorUtility.SetDirty(tfs[i]);\n                }\n            }\n        }\n\n        [MenuItem(\"CONTEXT/Transform/SetX\")]\n        public static void SetX(MenuCommand command)\n        {\n            var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.x).ToArray();\n            if (tfs.Length > 2)\n            {\n                Undo.RecordObjects(tfs, \"SetX\");\n                var startX = tfs[0].position.x;\n                var prevBound = tfs[0].GetBounds();\n                for (var i = 0; i < tfs.Length; i++)\n                {\n                    var dist = 0f;\n                    if (i > 0)\n                    {\n                        var bounds = tfs[i].GetBounds();\n                        dist = prevBound.extents.x + bounds.extents.x;\n                        prevBound = bounds;\n                    }\n\n                    var pos = tfs[i].position;\n                    pos.x = startX + dist;\n                    tfs[i].position = pos;\n                    startX = pos.x;\n                    EditorUtility.SetDirty(tfs[i]);\n                }\n            }\n        }\n\n        [MenuItem(\"CONTEXT/Transform/SetY\")]\n        public static void SetY(MenuCommand command)\n        {\n            var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.y).ToArray();\n            if (tfs.Length > 2)\n            {\n                Undo.RecordObjects(tfs, \"SetY\");\n                var startY = tfs[0].position.y;\n                var prevBound = tfs[0].GetBounds();\n                for (var i = 0; i < tfs.Length; i++)\n                {\n                    var dist = 0f;\n                    if (i > 0)\n                    {\n                        var bounds = tfs[i].GetBounds();\n                        dist = prevBound.extents.y + bounds.extents.y;\n                        prevBound = bounds;\n                    }\n\n                    var pos = tfs[i].position;\n                    pos.y = startY + dist;\n                    tfs[i].position = pos;\n                    startY = pos.y;\n                    EditorUtility.SetDirty(tfs[i]);\n                }\n            }\n        }\n\n        [MenuItem(\"CONTEXT/Transform/AlignX\")]\n        public static void AlignX(MenuCommand command)\n        {\n            var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.x).ToArray();\n            if (tfs.Length > 2)\n            {\n                Undo.RecordObjects(tfs, \"AlignX\");\n                var x = tfs[0].position.x;\n                for (var i = 0; i < tfs.Length; i++)\n                {\n                    var pos = tfs[i].position;\n                    pos.x = x;\n                    tfs[i].position = pos;\n                    EditorUtility.SetDirty(tfs[i]);\n                }\n            }\n        }\n\n        [MenuItem(\"CONTEXT/Transform/AlignY\")]\n        public static void AlignY(MenuCommand command)\n        {\n            var tfs = Selection.gameObjects.Select(g => g.transform).OrderBy(t => t.position.y).ToArray();\n            if (tfs.Length > 2)\n            {\n                Undo.RecordObjects(tfs, \"AlignY\");\n                var y = tfs[0].position.y;\n                for (var i = 0; i < tfs.Length; i++)\n                {\n                    var pos = tfs[i].position;\n                    pos.y = y;\n                    tfs[i].position = pos;\n                    EditorUtility.SetDirty(tfs[i]);\n                }\n            }\n        }\n#endif\n    }\n\n    public static class LayerMaskExtension\n    {\n        public static int ToGameObjectLayer(this LayerMask layerMask)\n        {\n            return (int)Mathf.Log(layerMask.value, 2);\n        }\n    }\n\n    public static class NavmeshExtension\n    {\n        public static bool IsReachDestination(this NavMeshAgent agent, float threshold = 0.1f)\n        {\n            return !agent.pathPending && agent.remainingDistance < agent.stoppingDistance + threshold;\n        }\n    }\n\n    public static class EnumerationExtensions\n    {\n        public static bool Has<T>(this Enum type, T value)\n        {\n            try\n            {\n                return (((int)(object)type & (int)(object)value) == (int)(object)value);\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public static bool Is<T>(this Enum type, T value)\n        {\n            try\n            {\n                return (int)(object)type == (int)(object)value;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n\n        public static T Add<T>(this Enum type, T value)\n        {\n            try\n            {\n                return (T)(object)(((int)(object)type | (int)(object)value));\n            }\n            catch (Exception ex)\n            {\n                throw new ArgumentException($\"Could not append value from enumerated type '{typeof(T).Name}'.\", ex);\n            }\n        }\n\n        public static T Remove<T>(this Enum type, T value)\n        {\n            try\n            {\n                return (T)(object)(((int)(object)type & ~(int)(object)value));\n            }\n            catch (Exception ex)\n            {\n                throw new ArgumentException($\"Could not remove value from enumerated type '{typeof(T).Name}'.\", ex);\n            }\n        }\n    }\n\n    public static class MathExtension\n    {\n        public static System.Numerics.Vector3 ToSysVector3(this Vector3 v)\n        {\n            return new System.Numerics.Vector3(v.x, v.y, v.z);\n        }\n\n        public static System.Numerics.Quaternion ToSysQuaternion(this Quaternion v)\n        {\n            return new System.Numerics.Quaternion(v.x, v.y, v.z, v.w);\n        }\n    }\n\n    public static class ParticleExtension\n    {\n        public static void SetSortingOrder(this ParticleSystem particle, int sortingOrder)\n        {\n            var ps = particle.GetComponentsInChildren<ParticleSystem>();\n            foreach (var p in ps)\n            {\n                var r = p.GetComponent<Renderer>();\n                r.sortingOrder += sortingOrder;\n            }\n        }\n\n        public static void SetStopAction(this ParticleSystem particle, ParticleSystemStopAction stopAction)\n        {\n            var main = particle.main;\n            main.stopAction = stopAction;\n        }\n    }\n\n    public static class FlipXExtension\n    {\n        public static void FlipX(this Transform target)\n        {\n            var pos = target.localPosition;\n            pos.x = -pos.x;\n            target.localPosition = pos;\n\n            var rot = target.localRotation;\n            rot *= Quaternion.Euler(0, 0, rot.y * 2);\n            target.localRotation = rot;\n        }\n\n        public static void FlipX(this PolygonCollider2D target)\n        {\n            var points = target.points;\n            for (var i = 0; i < points.Length; i++)\n            {\n                points[i].x = -points[i].x;\n            }\n\n            target.points = points;\n        }\n\n        public static void FlipX(this HingeJoint2D target)\n        {\n            var motor = target.motor;\n            motor.motorSpeed = -motor.motorSpeed;\n            target.motor = motor;\n        }\n\n        public static void FlipX(this BoxCollider2D target)\n        {\n            var offset = target.offset;\n            offset.x = -offset.x;\n            target.offset = offset;\n        }\n\n        public static void FlipX(this WheelJoint2D target)\n        {\n            var motor = target.motor;\n            motor.motorSpeed = -motor.motorSpeed;\n            target.motor = motor;\n        }\n\n#if UNITY_EDITOR\n        [MenuItem(\"CONTEXT/PolygonCollider2D/FlipX\")]\n        static void PolygonCollider2DFlipX(MenuCommand command)\n        {\n            var target = (PolygonCollider2D)command.context;\n            target.FlipX();\n\n            EditorUtility.SetDirty(target);\n        }\n\n        [MenuItem(\"CONTEXT/Transform/FlipX\")]\n        static void TransformFlipX(MenuCommand command)\n        {\n            var target = (Transform)command.context;\n            target.FlipX();\n\n            EditorUtility.SetDirty(target);\n        }\n\n        [MenuItem(\"CONTEXT/HingeJoint2D/FlipX\")]\n        static void HingeJoint2DFlipX(MenuCommand command)\n        {\n            var target = (HingeJoint2D)command.context;\n            target.FlipX();\n\n            EditorUtility.SetDirty(target);\n        }\n\n        [MenuItem(\"CONTEXT/BoxCollider2D/FlipX\")]\n        static void BoxCollider2DFlipX(MenuCommand command)\n        {\n            var target = (BoxCollider2D)command.context;\n            target.FlipX();\n\n            EditorUtility.SetDirty(target);\n        }\n\n        [MenuItem(\"CONTEXT/WheelJoint2D/FlipX\")]\n        static void WheelJoint2DFlipX(MenuCommand command)\n        {\n            var target = (WheelJoint2D)command.context;\n            target.FlipX();\n\n            EditorUtility.SetDirty(target);\n        }\n#endif\n    }\n\n    public class UnityWebRequestAwaiter : INotifyCompletion\n    {\n        UnityWebRequestAsyncOperation ao;\n        Action continuation;\n\n        public UnityWebRequestAwaiter(UnityWebRequestAsyncOperation ao)\n        {\n            this.ao = ao;\n            ao.completed += OnRequestCompleted;\n        }\n\n        public bool IsCompleted => ao.isDone;\n\n        public void GetResult()\n        {\n        }\n\n        public void OnCompleted(Action c)\n        {\n            continuation = c;\n        }\n\n        void OnRequestCompleted(AsyncOperation obj)\n        {\n            continuation();\n        }\n    }\n\n    public static class UnityWebRequestExtensions\n    {\n        public static UnityWebRequestAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOp)\n        {\n            return new UnityWebRequestAwaiter(asyncOp);\n        }\n    }\n\n    public static class DictionaryExtension\n    {\n        public static Dictionary<T, K> Clone<T, K>(this Dictionary<T, K> dict)\n        {\n            if (dict == null)\n            {\n                return null;\n            }\n\n            return dict.ToDictionary(i => i.Key, i => i.Value);\n        }\n\n        public static string ToString<T, K>(this Dictionary<T, K> dict)\n        {\n            if (dict == null)\n            {\n                return string.Empty;\n            }\n\n            return string.Join(\", \", dict);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ExtensionUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: d424096a405f4d10b578a33d12c66fd1\ntimeCreated: 1622039108"
  },
  {
    "path": "VirtueSky/Utils/Runtime/InputUtils.cs",
    "content": "﻿using System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.EventSystems;\n\nnamespace VirtueSky.Utils\n{\n    public class InputUtils\n    {\n        public static bool IsPointerOverUI(Vector2 pos)\n        {\n            var eventDataCurrentPosition = new PointerEventData(EventSystem.current)\n            {\n                position = new Vector2(pos.x, pos.y)\n            };\n            var results = new List<RaycastResult>();\n            EventSystem.current.RaycastAll(eventDataCurrentPosition, results);\n            return results.Count > 0;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/InputUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: b6fe19d3e11140659ebed2c0c0ef0ac1\ntimeCreated: 1630517731"
  },
  {
    "path": "VirtueSky/Utils/Runtime/InterfaceUtils.cs",
    "content": "﻿using System.Collections.Generic;\nusing UnityEngine.SceneManagement;\n\nnamespace VirtueSky.Utils\n{\n    public static class InterfaceUtils\n    {\n        public static List<T> GetAllInterfaces<T>()\n        {\n            var interfaces = new List<T>();\n            var rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();\n            foreach (var rootGameObject in rootGameObjects)\n            {\n                var childrenInterfaces = rootGameObject.GetComponentsInChildren<T>(true);\n                foreach (var childInterface in childrenInterfaces)\n                {\n                    interfaces.Add(childInterface);\n                }\n            }\n\n            return interfaces;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/InterfaceUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: f38899acc2024dee8832c6a518563565\ntimeCreated: 1631162887"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ReflectionUtils.cs",
    "content": "using System;\nusing System.Reflection;\n\nnamespace VirtueSky.Utils\n{\n    public static class ReflectionUtils\n    {\n        public static FieldInfo GetFieldRecursive(this Type type, string fieldName, BindingFlags bindingFlags)\n        {\n            var t = type;\n            FieldInfo field = null;\n            while (t != null)\n            {\n                field = t.GetField(fieldName, bindingFlags);\n                if (field != null) break;\n                t = t.BaseType;\n            }\n\n            return field;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ReflectionUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e093744796dd4fd19982333ec51c2ec5\ntimeCreated: 1658972648"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ScriptableSettings.cs",
    "content": "﻿namespace VirtueSky.Utils\n{\n    using UnityEngine;\n    using System;\n\n    public abstract class ScriptableSettings<T> : ScriptableObject where T : ScriptableObject\n    {\n        private static T instance;\n\n        public static T Instance\n        {\n            get\n            {\n                if (instance != null) return instance;\n\n                instance = Resources.Load<T>(typeof(T).Name);\n                if (instance == null)\n                    throw new Exception($\"Scriptable setting for {typeof(T)} must be create before run!\");\n                return instance;\n            }\n        }\n\n        public static bool IsExist() => Resources.Load<T>(typeof(T).Name) != null;\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/ScriptableSettings.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8433fcf2c3af43109ba905de77e68443\ntimeCreated: 1697171918"
  },
  {
    "path": "VirtueSky/Utils/Runtime/SimpleMath.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\nusing Random = UnityEngine.Random;\n\nnamespace VirtueSky.Utils\n{\n    public static class SimpleMath\n    {\n        public static bool InRange(Vector3 p, Vector3 c, float r, out float sqrDst, bool compareY = false)\n        {\n            if (!compareY) p.y = c.y;\n            sqrDst = SqrDist(p, c);\n            return sqrDst <= r * r;\n        }\n\n        public static bool InRange(Vector3 p, Vector3 c, float r, bool compareY = false)\n        {\n            if (!compareY) p.y = c.y;\n            var sqrDst = SqrDist(p, c);\n            return sqrDst <= r * r;\n        }\n\n        public static bool InRange2D(Vector2 p, Vector2 c, float r)\n        {\n            var sqrDst = SqrDist(p, c);\n            return sqrDst <= r * r;\n        }\n\n        public static float SqrDist(Vector3 a, Vector3 b)\n        {\n            return (a - b).sqrMagnitude;\n        }\n\n        public static Quaternion RandomRotation(bool onlyY = false)\n        {\n            if (onlyY) return Quaternion.Euler(0, Random.value * 360f, 0);\n            return Quaternion.Euler(RandomVector3() * 180f);\n        }\n\n        public static Quaternion GetRotationXZ(Vector3 a, Vector3 b)\n        {\n            var dir = b - a;\n            dir.y = 0;\n            if (dir != Vector3.zero)\n            {\n                return Quaternion.LookRotation(dir);\n            }\n            else\n            {\n                return Quaternion.identity;\n            }\n        }\n\n        public static Quaternion AngVelToDeriv(Quaternion current, Vector3 angVel)\n        {\n            var spin = new Quaternion(angVel.x, angVel.y, angVel.z, 0f);\n            var result = spin * current;\n            return new Quaternion(0.5f * result.x, 0.5f * result.y, 0.5f * result.z, 0.5f * result.w);\n        }\n\n        public static Vector3 DerivToAngVel(Quaternion current, Quaternion deriv)\n        {\n            var result = deriv * Quaternion.Inverse(current);\n            return new Vector3(2f * result.x, 2f * result.y, 2f * result.z);\n        }\n\n        public static Quaternion IntegrateRotation(Quaternion rotation, Vector3 angularVelocity, float deltaTime)\n        {\n            if (deltaTime < Mathf.Epsilon) return rotation;\n            var deriv = AngVelToDeriv(rotation, angularVelocity);\n            var pred = new Vector4(\n                rotation.x + deriv.x * deltaTime,\n                rotation.y + deriv.y * deltaTime,\n                rotation.z + deriv.z * deltaTime,\n                rotation.w + deriv.w * deltaTime\n            ).normalized;\n            return new Quaternion(pred.x, pred.y, pred.z, pred.w);\n        }\n\n        public static Quaternion QuaternionSmoothDamp(Quaternion rot, Quaternion target, ref Quaternion deriv,\n            float time)\n        {\n            if (Time.deltaTime < Mathf.Epsilon) return rot;\n            // account for double-cover\n            var dot = Quaternion.Dot(rot, target);\n            var multi = dot > 0f ? 1f : -1f;\n            target.x *= multi;\n            target.y *= multi;\n            target.z *= multi;\n            target.w *= multi;\n            // smooth damp (nlerp approx)\n            var result = new Vector4(\n                Mathf.SmoothDamp(rot.x, target.x, ref deriv.x, time),\n                Mathf.SmoothDamp(rot.y, target.y, ref deriv.y, time),\n                Mathf.SmoothDamp(rot.z, target.z, ref deriv.z, time),\n                Mathf.SmoothDamp(rot.w, target.w, ref deriv.w, time)\n            ).normalized;\n\n            // ensure deriv is tangent\n            var derivError = Vector4.Project(new Vector4(deriv.x, deriv.y, deriv.z, deriv.w), result);\n            deriv.x -= derivError.x;\n            deriv.y -= derivError.y;\n            deriv.z -= derivError.z;\n            deriv.w -= derivError.w;\n\n            return new Quaternion(result.x, result.y, result.z, result.w);\n        }\n\n        public static Vector3 RandomVector3(bool zeroY = false)\n        {\n            var result = Random.insideUnitSphere;\n            if (zeroY) result.y = 0;\n            return result;\n        }\n\n        public static int GetNearestIndex(Vector3 p, float r, Vector3[] list, bool compareY = false)\n        {\n            var minDist = Mathf.Infinity;\n            var index = -1;\n            var dist = 0f;\n            for (var i = 0; i < list.Length; i++)\n            {\n                if (InRange(p, list[i], r, out dist, compareY))\n                {\n                    if (dist <= minDist)\n                    {\n                        minDist = dist;\n                        index = i;\n                    }\n                }\n            }\n\n            return index;\n        }\n\n        public static Vector3 RandomBetween(Vector3 a, Vector3 b)\n        {\n            return a + (b - a).normalized * Random.value * (b - a).magnitude;\n        }\n\n        public static string NewGuid()\n        {\n            var encoded = Convert.ToBase64String(System.Guid.NewGuid().ToByteArray());\n            encoded = encoded.Replace(\"/\", \"_\").Replace(\"+\", \"-\");\n            return encoded.Substring(0, 22);\n        }\n\n\n        public static Vector3 DirectionFromAngle(float angleInDegrees)\n        {\n            return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad));\n        }\n\n        public static T[] SelectRandomFromArray<T>(T[] items, int count)\n        {\n            if (items.Length < count)\n            {\n                return items;\n            }\n\n            var list = items.ToList();\n            var result = new T[count];\n            while (list.Count > 0 && count > 0)\n            {\n                count--;\n                result[count] = list[Random.Range(0, list.Count)];\n                list.Remove(result[count]);\n            }\n\n            return result;\n        }\n\n        public static Vector3[] GetCirclePoint(Vector3 center, float radius, float step = 0.1f)\n        {\n            var points = new List<Vector3>();\n            var theta = 0f;\n            var x = radius * Mathf.Cos(theta);\n            var y = radius * Mathf.Sin(theta);\n            points.Add(center + new Vector3(x, 0, y));\n            for (theta = step; theta < Mathf.PI * 2; theta += step)\n            {\n                x = radius * Mathf.Cos(theta);\n                y = radius * Mathf.Sin(theta);\n                points.Add(center + new Vector3(x, 0, y));\n            }\n\n            return points.ToArray();\n        }\n\n        public static bool LinePlaneIntersection(out Vector3 intersection, Vector3 linePoint, Vector3 lineVec,\n            Vector3 planeNormal, Vector3 planePoint)\n        {\n            float length;\n            float dotNumerator;\n            float dotDenominator;\n            Vector3 vector;\n            intersection = Vector3.zero;\n\n            //calculate the distance between the linePoint and the line-plane intersection point\n            dotNumerator = Vector3.Dot((planePoint - linePoint), planeNormal);\n            dotDenominator = Vector3.Dot(lineVec, planeNormal);\n\n            //line and plane are not parallel\n            if (dotDenominator != 0.0f)\n            {\n                length = dotNumerator / dotDenominator;\n\n                //create a vector from the linePoint to the intersection point\n                vector = SetVectorLength(lineVec, length);\n\n                //get the coordinates of the line-plane intersection point\n                intersection = linePoint + vector;\n\n                return true;\n            }\n            //output not valid\n            else\n            {\n                return false;\n            }\n        }\n\n        public static bool AreLineSegmentsCrossing(Vector3 pointA1, Vector3 pointA2, Vector3 pointB1, Vector3 pointB2)\n        {\n            Vector3 closestPointA;\n            Vector3 closestPointB;\n            int sideA;\n            int sideB;\n\n            Vector3 lineVecA = pointA2 - pointA1;\n            Vector3 lineVecB = pointB2 - pointB1;\n\n            bool valid = ClosestPointsOnTwoLines(out closestPointA, out closestPointB, pointA1, lineVecA.normalized,\n                pointB1, lineVecB.normalized);\n\n            //lines are not parallel\n            if (valid)\n            {\n                sideA = PointOnWhichSideOfLineSegment(pointA1, pointA2, closestPointA);\n                sideB = PointOnWhichSideOfLineSegment(pointB1, pointB2, closestPointB);\n\n                if ((sideA == 0) && (sideB == 0))\n                {\n                    return true;\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        public static bool ClosestPointsOnTwoLines(out Vector3 closestPointLine1, out Vector3 closestPointLine2,\n            Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2)\n        {\n            closestPointLine1 = Vector3.zero;\n            closestPointLine2 = Vector3.zero;\n\n            float a = Vector3.Dot(lineVec1, lineVec1);\n            float b = Vector3.Dot(lineVec1, lineVec2);\n            float e = Vector3.Dot(lineVec2, lineVec2);\n\n            float d = a * e - b * b;\n\n            //lines are not parallel\n            if (d != 0.0f)\n            {\n                Vector3 r = linePoint1 - linePoint2;\n                float c = Vector3.Dot(lineVec1, r);\n                float f = Vector3.Dot(lineVec2, r);\n\n                float s = (b * f - c * e) / d;\n                float t = (a * f - c * b) / d;\n\n                closestPointLine1 = linePoint1 + lineVec1 * s;\n                closestPointLine2 = linePoint2 + lineVec2 * t;\n\n                return true;\n            }\n\n            else\n            {\n                return false;\n            }\n        }\n\n        public static int PointOnWhichSideOfLineSegment(Vector3 linePoint1, Vector3 linePoint2, Vector3 point)\n        {\n            Vector3 lineVec = linePoint2 - linePoint1;\n            Vector3 pointVec = point - linePoint1;\n\n            float dot = Vector3.Dot(pointVec, lineVec);\n\n            //point is on side of linePoint2, compared to linePoint1\n            if (dot > 0)\n            {\n                //point is on the line segment\n                if (pointVec.magnitude <= lineVec.magnitude)\n                {\n                    return 0;\n                }\n\n                //point is not on the line segment and it is on the side of linePoint2\n                else\n                {\n                    return 2;\n                }\n            }\n\n            //Point is not on side of linePoint2, compared to linePoint1.\n            //Point is not on the line segment and it is on the side of linePoint1.\n            else\n            {\n                return 1;\n            }\n        }\n\n        public static Vector3 SetVectorLength(Vector3 vector, float size)\n        {\n            //normalize the vector\n            var vectorNormalized = Vector3.Normalize(vector);\n\n            //scale the vector\n            return vectorNormalized *= size;\n        }\n\n        public static Color DotColor(Color a, Color b)\n        {\n            var vA = new Vector3(a.r, a.g, a.b);\n            var vB = new Vector3(b.r, b.g, b.b);\n            var vC = Vector3.Dot(vA, vB);\n            return new Color(vC, vC, vC);\n        }\n\n        public static T GetRandomWithWeight<T>(T[] items, int[] weights)\n        {\n            var totalWeight = weights.Sum();\n            var rd = Random.Range(0, totalWeight);\n            var sumWeight = 0;\n            var result = items[0];\n            for (var i = 0; i < items.Length; i++)\n            {\n                sumWeight += weights[i];\n                if (rd < sumWeight)\n                {\n                    result = items[i];\n                    break;\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/SimpleMath.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 596eb1042e0345789ff57fc696c2de73\ntimeCreated: 1598278587"
  },
  {
    "path": "VirtueSky/Utils/Runtime/StoreUtils.cs",
    "content": "﻿using UnityEngine;\n\nnamespace VirtueSky.Utils\n{\n    public static class StoreUtils\n    {\n        public static void OpenStore()\n        {\n#if UNITY_ANDROID\n            Application.OpenURL($\"market://details?id={Application.identifier}\");\n#elif UNITY_IPHONE\n            Application.OpenURL(\"itms-apps://itunes.apple.com/app/1598593737\");\n#endif\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/StoreUtils.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 95bee5da44516954396fb291ece7ae5f\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Runtime/TimeUtils.cs",
    "content": "﻿using System;\n\nnamespace VirtueSky.Utils\n{\n    public static class TimeUtils\n    {\n        public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0);\n        public static readonly DateTime EpochUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);\n\n        public static DateTime Now => DateTime.Now;\n        public static long CurrentTicks => DateTime.Now.Ticks - Epoch.Ticks;\n\n        public static long CurrentTicksUtc => DateTime.UtcNow.Ticks - EpochUtc.Ticks;\n\n        public static long CurrentDays => CurrentTicks / TimeSpan.TicksPerDay;\n\n        public static double CurrentSeconds => TicksToSeconds(CurrentTicks);\n\n        public static double CurrentSecondsUtc => TicksToSeconds(CurrentTicksUtc);\n\n        public static DateTime TicksToDateTime(long ticks)\n        {\n            var date = Epoch + TimeSpan.FromTicks(ticks);\n            return date.ToLocalTime();\n        }\n\n        public static DateTime SecondsToDateTime(double seconds)\n        {\n            var date = Epoch + TimeSpan.FromSeconds(seconds);\n            return date;\n        }\n\n        public static double TimespanSeconds(long ticks, long lastTicks)\n        {\n            return TimeSpan.FromTicks(ticks - lastTicks).TotalSeconds;\n        }\n\n        public static double TimespanHours(long ticks, long lastTicks)\n        {\n            return TimeSpan.FromTicks(ticks - lastTicks).TotalHours;\n        }\n\n        public static long SecondsToTicks(double seconds)\n        {\n            return (long)(seconds * TimeSpan.TicksPerSecond);\n        }\n\n        public static int SecondsToMiniseconds(double seconds)\n        {\n            return (int)(seconds * 1000);\n        }\n\n        public static double MinisecondsToSeconds(int miniseconds)\n        {\n            return (double)(miniseconds / 1000f);\n        }\n\n        public static double TicksToSeconds(long ticks)\n        {\n            return (double)ticks / TimeSpan.TicksPerSecond;\n        }\n\n        public static long SecondsToDays(double seconds)\n        {\n            return SecondsToTicks(seconds) / TimeSpan.TicksPerDay;\n        }\n\n        public static double DaysToSeconds(long days)\n        {\n            return TimeSpan.FromDays(days).TotalSeconds;\n        }\n\n        public static string FormatTimeSpan(double seconds)\n        {\n            var span = new TimeSpan(SecondsToTicks(seconds));\n            return span.Days > 0 ? $\"{span.Days}:{span.Hours:00}:{span.Minutes:00}:{span.Seconds:00}\" :\n                span.Hours > 0 ? $\"{span.Hours:00}:{span.Minutes:00}:{span.Seconds:00}\" :\n                $\"{span.Minutes:00}:{span.Seconds:00}\";\n        }\n\n        public static string FormatTimeSpanExcludeSecond(double seconds)\n        {\n            var span = new TimeSpan(SecondsToTicks(seconds));\n            return span.Hours > 0 ? $\"{span.Hours:00}h:{span.Minutes:00}min\" : $\"{span.Minutes:00}min\";\n        }\n\n        public static float TargetTimeScale { get; set; } = 1;\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/TimeUtils.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 56cb55840fb34aedb0e10253d754d60c\ntimeCreated: 1596822219"
  },
  {
    "path": "VirtueSky/Utils/Runtime/TweenStatic.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\n\nnamespace PrimeTween\n{\n    public static class TweenStatic\n    {\n        // target, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime\n        // target, startValue, endValue, duration, ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime\n\n        #region EulerAngles\n\n        public static Tween EulerAngles([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.EulerAngles(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalEulerAngles([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalEulerAngles(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Position\n\n        public static Tween Position([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Position(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween Position([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.Position(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween PositionAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float averageSpeed, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionAtSpeed(target, endValue, averageSpeed, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween PositionAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float averageSpeed,\n            Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionAtSpeed(target, startValue, endValue, averageSpeed, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        // X\n        public static Tween PositionX([NotNull] this UnityEngine.Transform target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionX(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween PositionX([NotNull] this UnityEngine.Transform target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionX(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        // Y\n        public static Tween PositionY([NotNull] this UnityEngine.Transform target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionY(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween PositionY([NotNull] this UnityEngine.Transform target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionY(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        // Z\n        public static Tween PositionZ([NotNull] this UnityEngine.Transform target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionZ(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween PositionZ([NotNull] this UnityEngine.Transform target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.PositionZ(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Local Position\n\n        public static Tween LocalPosition([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPosition(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalPosition([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.LocalPosition(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalPositionAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float averageSpeed, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionAtSpeed(target, endValue, averageSpeed, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalPositionAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float averageSpeed,\n            Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart,\n            float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionAtSpeed(target, startValue, endValue, averageSpeed, ease,\n                cycles, cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        // X\n        public static Tween LocalPositionX([NotNull] this UnityEngine.Transform target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionX(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalPositionX([NotNull] this UnityEngine.Transform target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionX(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        // Y\n        public static Tween LocalPositionY([NotNull] this UnityEngine.Transform target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionY(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalPositionY([NotNull] this UnityEngine.Transform target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionY(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        // Z\n        public static Tween LocalPositionZ([NotNull] this UnityEngine.Transform target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionZ(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalPositionZ([NotNull] this UnityEngine.Transform target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalPositionZ(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Rotation\n\n        public static Tween Rotation([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Rotation(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween Rotation([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.Rotation(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween RotationAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Quaternion endValue, float averageAngularSpeed, Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.RotationAtSpeed(target, endValue, averageAngularSpeed, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween RotationAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Quaternion startValue, UnityEngine.Quaternion endValue,\n            float averageAngularSpeed,\n            Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart,\n            float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.RotationAtSpeed(target, startValue, endValue, averageAngularSpeed, ease,\n                cycles, cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Local Rotation\n\n        public static Tween LocalRotation([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalRotation(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalRotation([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.LocalRotation(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalRotationAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Quaternion endValue, float averageAngularSpeed, Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.LocalRotationAtSpeed(target, endValue, averageAngularSpeed, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween LocalRotationAtSpeed([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Quaternion startValue, UnityEngine.Quaternion endValue,\n            float averageAngularSpeed, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.LocalRotationAtSpeed(target, startValue, endValue, averageAngularSpeed,\n                ease, cycles, cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Scale\n\n        public static Tween Scale([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.Scale(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween Scale([NotNull] this UnityEngine.Transform target,\n            UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Scale(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween ScaleX([NotNull] this UnityEngine.Transform target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.ScaleX(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween ScaleX([NotNull] this UnityEngine.Transform target, Single startValue,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.ScaleX(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween ScaleY([NotNull] this UnityEngine.Transform target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.ScaleY(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween ScaleY([NotNull] this UnityEngine.Transform target, Single startValue,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.ScaleY(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween ScaleZ([NotNull] this UnityEngine.Transform target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.ScaleZ(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween ScaleZ([NotNull] this UnityEngine.Transform target, Single startValue,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.ScaleZ(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Color SpriteRenderer\n\n        public static Tween Color([NotNull] this UnityEngine.SpriteRenderer target,\n            UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Color(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween Color([NotNull] this UnityEngine.SpriteRenderer target,\n            UnityEngine.Color startValue, UnityEngine.Color endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.Color(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween Alpha([NotNull] this UnityEngine.SpriteRenderer target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Alpha(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween Alpha([NotNull] this UnityEngine.SpriteRenderer target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Alpha(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Camera\n\n        public static Tween CameraOrthographicSize([NotNull] this UnityEngine.Camera target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraOrthographicSize(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraOrthographicSize([NotNull] this UnityEngine.Camera target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.CameraOrthographicSize(target, startValue, endValue, duration, ease,\n                cycles, cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraBackgroundColor([NotNull] this UnityEngine.Camera target,\n            UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraBackgroundColor(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraBackgroundColor([NotNull] this UnityEngine.Camera target,\n            UnityEngine.Color startValue, UnityEngine.Color endValue, float duration,\n            Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraBackgroundColor(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraAspect([NotNull] this UnityEngine.Camera target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraAspect(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraAspect([NotNull] this UnityEngine.Camera target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraAspect(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraFarClipPlane([NotNull] this UnityEngine.Camera target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraFarClipPlane(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraFarClipPlane([NotNull] this UnityEngine.Camera target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraFarClipPlane(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraFieldOfView([NotNull] this UnityEngine.Camera target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraFieldOfView(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraFieldOfView([NotNull] this UnityEngine.Camera target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraFieldOfView(target, startDelay, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraNearClipPlane([NotNull] this UnityEngine.Camera target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraNearClipPlane(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween CameraNearClipPlane([NotNull] this UnityEngine.Camera target,\n            Single startvalue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.CameraNearClipPlane(target, startvalue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Color UI Graphic\n\n        public static Tween Color([NotNull] this UnityEngine.UI.Graphic target,\n            UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Color(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween Color([NotNull] this UnityEngine.UI.Graphic target,\n            UnityEngine.Color startValue, UnityEngine.Color endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.Color(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween Alpha([NotNull] this UnityEngine.UI.Graphic target, Single endValue,\n            float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Alpha(target, endValue, duration, ease, cycles, cycleMode, startDelay,\n                endDelay, useUnscaledTime);\n        }\n\n        public static Tween Alpha([NotNull] this UnityEngine.UI.Graphic target, Single startValue,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.Alpha(target, startValue, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region UI Image\n\n        public static Tween UIFillAmount([NotNull] this UnityEngine.UI.Image target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.UIFillAmount(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween UIFillAmount([NotNull] this UnityEngine.UI.Image target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.UIFillAmount(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Rigidbody\n\n        public static Tween RigidbodyMovePosition([NotNull] this UnityEngine.Rigidbody target,\n            UnityEngine.Vector3 endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMovePosition(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween RigidbodyMovePosition([NotNull] this UnityEngine.Rigidbody target,\n            UnityEngine.Vector3 startValue, UnityEngine.Vector3 endValue, float duration,\n            Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart,\n            float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMovePosition(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween RigidbodyMoveRotation([NotNull] this UnityEngine.Rigidbody target,\n            UnityEngine.Quaternion endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMoveRotation(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween RigidbodyMoveRotation([NotNull] this UnityEngine.Rigidbody target,\n            UnityEngine.Quaternion startValue, UnityEngine.Quaternion endValue, float duration,\n            Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart,\n            float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMoveRotation(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Rigidbody2D\n\n        public static Tween Rigidbody2DMovePosition([NotNull] this UnityEngine.Rigidbody2D target,\n            UnityEngine.Vector2 endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMovePosition(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween Rigidbody2DMovePosition([NotNull] this UnityEngine.Rigidbody2D target,\n            UnityEngine.Vector2 startValue, UnityEngine.Vector2 endValue, float duration,\n            Ease ease = Ease.Default, int cycles = 1, CycleMode cycleMode = CycleMode.Restart,\n            float startDelay = 0, float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMovePosition(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween Rigidbody2DMoveRotation([NotNull] this UnityEngine.Rigidbody2D target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMoveRotation(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween Rigidbody2DMoveRotation([NotNull] this UnityEngine.Rigidbody2D target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.RigidbodyMoveRotation(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n\n        #region Material\n\n        public static Tween MaterialColor([NotNull] this UnityEngine.Material target,\n            UnityEngine.Color endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.MaterialColor(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween MaterialColor([NotNull] this UnityEngine.Material target,\n            UnityEngine.Color startValue, UnityEngine.Color endValue, float duration,\n            Ease ease = Ease.Default,\n            int cycles = 1, CycleMode cycleMode = CycleMode.Restart, float startDelay = 0,\n            float endDelay = 0, bool useUnscaledTime = false)\n        {\n            return Tween.MaterialColor(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween MaterialAlpha([NotNull] this UnityEngine.Material target,\n            Single endValue, float duration, Ease ease = Ease.Default, int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.MaterialAlpha(target, endValue, duration, ease, cycles, cycleMode,\n                startDelay, endDelay, useUnscaledTime);\n        }\n\n        public static Tween MaterialAlpha([NotNull] this UnityEngine.Material target,\n            Single startValue, Single endValue, float duration, Ease ease = Ease.Default,\n            int cycles = 1,\n            CycleMode cycleMode = CycleMode.Restart, float startDelay = 0, float endDelay = 0,\n            bool useUnscaledTime = false)\n        {\n            return Tween.MaterialAlpha(target, startValue, endValue, duration, ease, cycles,\n                cycleMode, startDelay, endDelay, useUnscaledTime);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/TweenStatic.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 738f4f5e3c9b4ab88264a46f0edf74b3\ntimeCreated: 1701418240"
  },
  {
    "path": "VirtueSky/Utils/Runtime/Virtuesky.Sunflower.Utils.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Utils\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:80ecb87cae9c44d19824e70ea7229748\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Utils/Runtime/Virtuesky.Sunflower.Utils.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: c282fd4f3fc2c7540914e85842a013c7\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Utils/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: 770dace87f564d0faf67c561c84f0051\ntimeCreated: 1699932112"
  },
  {
    "path": "VirtueSky/Utils.meta",
    "content": "fileFormatVersion: 2\nguid: 2d0ca7a47dfd41541bb113dfd19ac5e8\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Editor/VariableGenerateGuid.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing VirtueSky.Core;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.Variables\n{\n    internal class VariableGenerateGuid : AssetPostprocessor\n    {\n        private static readonly HashSet<string> GuidsVariableCache = new HashSet<string>();\n        private const string Key_Init_Session = \"Key_Init_Session\";\n\n        private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets,\n            string[] movedAssets,\n            string[] movedFromAssetPaths)\n        {\n            bool isInit = SessionState.GetBool(Key_Init_Session, false);\n            if (!isInit)\n            {\n                CacheAllGuids();\n                SessionState.SetBool(Key_Init_Session, true);\n            }\n            else\n            {\n                OnImportAsset(importedAssets);\n                OnAssetDeleted(deletedAssets);\n                OnAssetMoved(movedFromAssetPaths, movedAssets);\n            }\n        }\n\n        static void CacheAllGuids()\n        {\n            var baseVariables = FileExtension.FindAll<BaseSO>();\n            foreach (var variable in baseVariables)\n            {\n                if (variable is IGuidVariable iGuidVariable)\n                {\n                    iGuidVariable.Guid = GenerateGuid(variable);\n                    GuidsVariableCache.Add(iGuidVariable.Guid);\n                }\n            }\n        }\n\n        static void OnImportAsset(string[] importedAssets)\n        {\n            foreach (var path in importedAssets)\n            {\n                if (GuidsVariableCache.Contains(path)) continue;\n                var asset = AssetDatabase.LoadAssetAtPath<BaseSO>(path);\n                if (asset == null || asset is not IGuidVariable iGuidVariable) continue;\n                iGuidVariable.Guid = GenerateGuid(asset);\n                GuidsVariableCache.Add(iGuidVariable.Guid);\n            }\n        }\n\n        static void OnAssetDeleted(string[] deletedAssets)\n        {\n            foreach (var path in deletedAssets)\n            {\n                if (!GuidsVariableCache.Contains(path)) continue;\n                GuidsVariableCache.Remove(path);\n            }\n        }\n\n        static void OnAssetMoved(string[] movedFromAssetPaths, string[] movedAssets)\n        {\n            OnAssetDeleted(movedFromAssetPaths);\n            OnImportAsset(movedAssets);\n        }\n\n        private static string GenerateGuid(ScriptableObject scriptableObject)\n        {\n            return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(scriptableObject));\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Editor/VariableGenerateGuid.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7dec4410dffa4b5dbb78a9f5ab26c621\ntimeCreated: 1717470269"
  },
  {
    "path": "VirtueSky/Variables/Editor/VariableWindowEditor.cs",
    "content": "using Microsoft.Win32.SafeHandles;\nusing UnityEditor;\nusing VirtueSky.UtilsEditor;\n\nnamespace VirtueSky.Variables\n{\n#if UNITY_EDITOR\n    public class VariableWindowEditor : EditorWindow\n    {\n        #region Create ScriptableObject Variable\n\n        private const string pathVariable = \"/Variable\";\n        private const string menuVariable = \"Sunflower/Scriptable/Create Variable/\";\n\n        [MenuItem(menuVariable + \"Transform Variable\", priority = 201)]\n        public static void CreateVariableTransform()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<TransformVariable>(pathVariable,\n                \"so_transform_variable\");\n        }\n\n        [MenuItem(menuVariable + \"Rect Variable\", priority = 201)]\n        public static void CreateVariableRect()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<RectVariable>(pathVariable, \"so_rect_variable\");\n        }\n\n        [MenuItem(menuVariable + \"Object Variable\", priority = 201)]\n        public static void CreateVariableObject()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<ObjectVariable>(pathVariable, \"so_object_variables\");\n        }\n\n        [MenuItem(menuVariable + \"Boolean Variable\", priority = 201)]\n        public static void CreateVariableBoolean()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<BooleanVariable>(pathVariable, \"so_bool_variables\");\n        }\n\n        [MenuItem(menuVariable + \"Short Double Variable\", priority = 201)]\n        public static void CreateVariableShortDouble()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<ShortDoubleVariable>(pathVariable,\n                \"so_short_double_variable\");\n        }\n\n        [MenuItem(menuVariable + \"Vector3 Variable\", priority = 201)]\n        public static void CreateVariableVector3()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<Vector3Variable>(pathVariable, \"so_vector3_variable\");\n        }\n\n        [MenuItem(menuVariable + \"Vector2 Variable\", priority = 201)]\n        public static void CreateVariableVector2()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<Vector2Variable>(pathVariable, \"so_vector2_variable\");\n        }\n\n        [MenuItem(menuVariable + \"String Variable\", priority = 201)]\n        public static void CreateVariableString()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<StringVariable>(pathVariable, \"so_string_variable\");\n        }\n\n        [MenuItem(menuVariable + \"Float Variable\", priority = 201)]\n        public static void CreateVariableFloat()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<FloatVariable>(pathVariable, \"so_float_variables\");\n        }\n\n        [MenuItem(menuVariable + \"Integer Variable\", priority = 201)]\n        public static void CreateVariableInt()\n        {\n            var so = CreateAsset.CreateScriptableAssetsOnlyName<IntegerVariable>(pathVariable, \"so_int_variable\");\n        }\n\n        #endregion\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Variables/Editor/VariableWindowEditor.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8592c1130efe1ab448a38c88f5fa3145\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Editor/virtuesky.sunflower.variable.Editor.asmdef",
    "content": "{\n    \"name\": \"virtuesky.sunflower.variable.Editor\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:c904f6d969e991d459a0843b71c22ec5\",\n        \"GUID:35d694408290717499b3838802212c7f\",\n        \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n        \"GUID:acb3cac55c622ec459c8caadf707623a\",\n        \"GUID:540154dd0c5ed9a4dbbe695c402232fb\"\n    ],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Variables/Editor/virtuesky.sunflower.variable.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: e0f213a0782f8f74b8e336c82c8f43b8\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 35064efc1121d03469ef2454a60d7267\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/BaseReference.cs",
    "content": "using System;\nusing UnityEditor;\nusing UnityEngine;\n#if UNITY_EDITOR\n#endif\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class BaseReference : IReference\n    {\n    }\n\n    [Serializable]\n    public class BaseReference<TType, TVariable> : BaseReference, IReference<TType, TVariable>\n        where TVariable : BaseVariable<TType>\n    {\n        [SerializeField] bool useVariable;\n        [SerializeField] TType constantValue;\n        [SerializeField] TVariable variable;\n\n        public TType Value\n        {\n            get => useVariable ? variable.Value : constantValue;\n            set\n            {\n                if (useVariable)\n                {\n                    variable.Value = value;\n                }\n                else\n                {\n                    constantValue = value;\n                }\n            }\n        }\n\n        public override string ToString()\n        {\n            return Value.ToString();\n        }\n    }\n\n#if UNITY_EDITOR\n    [CustomPropertyDrawer(typeof(BaseReference), true)]\n    public sealed class BaseReferenceDrawer : PropertyDrawer\n    {\n        static readonly string[] popupOptions =\n        {\n            \"Use Constant\",\n            \"Use Variable\"\n        };\n\n        SerializedProperty property;\n        SerializedProperty useVariable;\n        SerializedProperty constantValue;\n        SerializedProperty variable;\n\n        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)\n        {\n            this.property = property;\n            useVariable = property.FindPropertyRelative(\"useVariable\");\n            constantValue = property.FindPropertyRelative(\"constantValue\");\n            variable = property.FindPropertyRelative(\"variable\");\n\n            var oldIndent = ResetIndent();\n\n            var fieldRect = DrawLabel(position, property, label);\n            var valueRect = DrawField(position, fieldRect);\n            DrawValue(position, valueRect);\n\n            EndIndent(oldIndent);\n\n            property.serializedObject.ApplyModifiedProperties();\n        }\n\n        Rect DrawLabel(Rect position, SerializedProperty property, GUIContent label)\n        {\n            return EditorGUI.PrefixLabel(position, label);\n        }\n\n        Rect DrawField(Rect position, Rect fieldRect)\n        {\n            var buttonRect = GetPopupButtonRect(fieldRect);\n            var valueRect = GetValueRect(fieldRect, buttonRect);\n\n            var result = DrawPopupButton(buttonRect, useVariable.boolValue ? 1 : 0);\n            useVariable.boolValue = result == 1;\n\n            return valueRect;\n        }\n\n        void DrawValue(Rect position, Rect valueRect)\n        {\n            if (useVariable.boolValue)\n            {\n                EditorGUI.PropertyField(valueRect, variable, GUIContent.none);\n            }\n            else\n            {\n                DrawGenericPropertyField(position, valueRect);\n            }\n        }\n\n        void DrawGenericPropertyField(Rect position, Rect valueRect)\n        {\n            EditorGUI.PropertyField(valueRect, constantValue, GUIContent.none);\n        }\n\n        int ResetIndent()\n        {\n            var indent = EditorGUI.indentLevel;\n            EditorGUI.indentLevel = 0;\n\n            return indent;\n        }\n\n        void EndIndent(int indent)\n        {\n            EditorGUI.indentLevel = indent;\n        }\n\n        int DrawPopupButton(Rect rect, int value)\n        {\n            return EditorGUI.Popup(rect, value, popupOptions, Styles.PopupStyle);\n        }\n\n        Rect GetValueRect(Rect fieldRect, Rect buttonRect)\n        {\n            var valueRect = new Rect(fieldRect);\n            valueRect.x += buttonRect.width;\n            valueRect.width -= buttonRect.width;\n\n            return valueRect;\n        }\n\n        Rect GetPopupButtonRect(Rect fieldrect)\n        {\n            var buttonRect = new Rect(fieldrect);\n            buttonRect.yMin += Styles.PopupStyle.margin.top;\n            buttonRect.width = Styles.PopupStyle.fixedWidth + Styles.PopupStyle.margin.right;\n            buttonRect.height = Styles.PopupStyle.fixedHeight + Styles.PopupStyle.margin.top;\n\n            return buttonRect;\n        }\n\n        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)\n        {\n            return EditorGUIUtility.singleLineHeight;\n        }\n\n        static class Styles\n        {\n            static Styles()\n            {\n                PopupStyle = new GUIStyle(GUI.skin.GetStyle(\"PaneOptions\"))\n                {\n                    imagePosition = ImagePosition.ImageOnly,\n                };\n            }\n\n            public static GUIStyle PopupStyle { get; set; }\n        }\n    }\n#endif\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/BaseReference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: e2fd30b177734d4d8a02e823ec21b503\ntimeCreated: 1651588713"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/BaseVariable.cs",
    "content": "using System;\nusing UnityEditor;\nusing UnityEngine;\nusing UnityEngine.Serialization;\nusing VirtueSky.DataStorage;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\nusing VirtueSky.Utils;\n\nnamespace VirtueSky.Variables\n{\n    public class BaseVariable<TType> : BaseEvent<TType>, IVariable<TType>, ISerializationCallbackReceiver, IGuidVariable\n    {\n        [TitleColor(\"Id\", CustomColor.Gold, CustomColor.Aqua), ShowIf(nameof(isSetData)), SerializeField]\n        private TypeId typeId;\n\n        [ShowIf(nameof(IsShowGuid)), ReadOnly, SerializeField]\n        protected string guid;\n\n        [ShowIf(nameof(IsShowCustomId)), SerializeField]\n        private string customId;\n\n\n        [TitleColor(\"Init value\", CustomColor.Chartreuse, CustomColor.OrangeVariant), Tooltip(\"Set initial value for scriptable variable\"), SerializeField]\n        protected TType initializeValue;\n\n        [TitleColor(\"Save Data\", CustomColor.Tomato, CustomColor.MediumSpringGreen),\n         Tooltip(\"Set data into dictionary, if not set data then scriptable variable will action as runtime variable\"),\n         SerializeField]\n        protected bool isSetData;\n\n        [Tooltip(\n             \"Save data from dictionary to file when value is changed. If not saved, data will be saved to file when game is paused or quit\"),\n         ShowIf(nameof(isSetData)), SerializeField]\n        protected bool isSaveData;\n\n        [TitleColor(\"Raise event\", CustomColor.DeepSkyBlue, CustomColor.Magenta), Tooltip(\"Raise event when value is changed\"), SerializeField]\n        protected bool isRaiseEvent;\n\n        [NonSerialized] protected TType runtimeValue;\n#if UNITY_EDITOR\n        [ShowIf(nameof(ConditionShow))] [ReadOnly, SerializeField]\n        protected TType currentValue;\n#endif\n        public TType InitializeValue => initializeValue;\n\n        public string Guid\n        {\n            get => guid;\n            set => guid = value;\n        }\n\n        public string CustomId\n        {\n            get => customId;\n            set => customId = value;\n        }\n\n        public string Id => typeId switch\n        {\n            TypeId.Guid => guid,\n            _ => customId,\n        };\n\n        private void OnEnable()\n        {\n#if UNITY_EDITOR\n            currentValue = Value;\n#endif\n        }\n\n        public virtual TType Value\n        {\n            get => isSetData ? GameData.Get(Id, initializeValue) : runtimeValue;\n            set\n            {\n                if (isSetData)\n                {\n                    GameData.Set(Id, value);\n                    if (isSaveData)\n                    {\n                        GameData.Save();\n                    }\n                }\n                else\n                {\n                    runtimeValue = value;\n                }\n#if UNITY_EDITOR\n                currentValue = value;\n#endif\n                if (isRaiseEvent)\n                {\n                    Raise(value);\n                }\n            }\n        }\n\n        public void OnBeforeSerialize()\n        {\n        }\n\n        public void OnAfterDeserialize()\n        {\n            runtimeValue = initializeValue;\n        }\n\n        public void ResetValue()\n        {\n            Value = initializeValue;\n        }\n\n        public override string ToString()\n        {\n            return Value.ToString();\n        }\n\n        private bool IsShowGuid => isSetData && typeId == TypeId.Guid;\n        private bool IsShowCustomId => isSetData && typeId == TypeId.CustomId;\n    }\n\n    public enum TypeId\n    {\n        Guid,\n        CustomId\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/BaseVariable.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 354f4bae410149e59e0ac1eec4ddc1e5\ntimeCreated: 1651587715"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/BaseVariableListener.cs",
    "content": "﻿using System;\nusing UnityEngine;\nusing UnityEngine.Events;\nusing VirtueSky.Events;\n\nnamespace VirtueSky.Variables\n{\n    public class BaseVariableListener<TType, TEvent, TResponse> : BaseEventListener<TType, TEvent, TResponse>\n        where TEvent : BaseVariable<TType>\n        where TResponse : UnityEvent<TType>\n    {\n        [SerializeField] private bool isRaisedOnStart;\n        [SerializeField] private bool isRaisedOnEnable;\n\n        private void Start()\n        {\n            if (isRaisedOnStart)\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    OnEventRaised(t.@event, t.@event.Value);\n                }\n            }\n        }\n\n        private void OnEnable()\n        {\n            if (isRaisedOnEnable)\n            {\n                foreach (var t in listEventResponseDatas)\n                {\n                    OnEventRaised(t.@event, t.@event.Value);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/BaseVariableListener.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 618fae92af2d4fd59f81d8f97daf73a6\ntimeCreated: 1660205495"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/IGuidVariable.cs",
    "content": "namespace VirtueSky.Variables\n{\n    public interface IGuidVariable\n    {\n        string Guid { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable/IGuidVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 616d5824d15f4a978da0254f5a5e52f2\ntimeCreated: 1717471847"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Base_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 98e06be1c92b45a46a3457b3793ed394\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable/BooleanReference.cs",
    "content": "using System;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class BooleanReference : BaseReference<bool, BooleanVariable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable/BooleanReference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 5afc2b5361de44a59b143ce9db37d46f\ntimeCreated: 1659149814"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariable.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Boolean\", fileName = \"bool_variables\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class BooleanVariable : BaseVariable<bool>\n    {\n        public void Toggle()\n        {\n            Value = !Value;\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 8612af88fd55455ab06a565de64186b9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariableListener.cs",
    "content": "using VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class BooleanVariableListener : BaseVariableListener<bool, BooleanVariable, BooleanEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable/BooleanVariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4b3c2acc31f54b44bda55b648b827ab6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Boolean_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 2456a56fac0d9b44b97d3dd3a7b95a2c\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable/FloatReference.cs",
    "content": "using System;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class FloatReference : BaseReference<float, FloatVariable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable/FloatReference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 1e5ea93b60834733af1822c26b795c31\ntimeCreated: 1651588790"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable/FloatVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.DataStorage;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Float\", fileName = \"float_variables\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class FloatVariable : BaseVariable<float>\n    {\n        [Tooltip(\"Clamps the value of this variable to a minimum and maximum.\")] [SerializeField]\n        private bool isClamped;\n\n        [Tooltip(\"If clamped, sets the minimum and maximum\")] [SerializeField, ShowIf(nameof(isClamped)), Indent]\n        private Vector2 minMax = new(0, 100);\n\n        public bool IsClamped => isClamped;\n\n        public Vector2 MinMax\n        {\n            get => minMax;\n            set => minMax = value;\n        }\n\n        public float Min\n        {\n            get => minMax.x;\n            set => minMax.x = value;\n        }\n\n        public float Max\n        {\n            get => minMax.y;\n            set => minMax.y = value;\n        }\n\n        public void Add(float value)\n        {\n            Value += value;\n        }\n\n        public override float Value\n        {\n            get => isSetData ? GameData.Get(Id, initializeValue) : runtimeValue;\n            set\n            {\n                var clampedValue = IsClamped ? Mathf.Clamp(value, minMax.x, minMax.y) : value;\n                if (isSetData)\n                {\n                    GameData.Set(Id, clampedValue);\n                    if (isSaveData)\n                    {\n                        GameData.Save();\n                    }\n                }\n                else\n                {\n                    runtimeValue = clampedValue;\n                }\n#if UNITY_EDITOR\n                currentValue = clampedValue;\n#endif\n                if (isRaiseEvent)\n                {\n                    Raise(clampedValue);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable/FloatVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e09883a9e2054c19929fd8b3292fa7d9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable/FloatVariableListener.cs",
    "content": "﻿using VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class FloatVariableListener : BaseVariableListener<float, FloatVariable, FloatEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable/FloatVariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a246834ae1b84ef38132800b51b86cfe\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Float_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 490c536cfc45de945833bdbfddd86b24\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable/IntegerReference.cs",
    "content": "using System;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class IntegerReference : BaseReference<int, IntegerVariable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable/IntegerReference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 4848f429140e4efcbf42ee9e910e9bb3\ntimeCreated: 1659595428"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.DataStorage;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Integer\", fileName = \"int_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class IntegerVariable : BaseVariable<int>\n    {\n        [Tooltip(\"Clamps the value of this variable to a minimum and maximum.\")] [SerializeField]\n        private bool isClamped;\n\n        public bool IsClamped => isClamped;\n\n        [Tooltip(\"If clamped, sets the minimum and maximum\")] [SerializeField, ShowIf(nameof(isClamped)), Indent]\n        private Vector2Int minMax = new(0, 100);\n\n        public Vector2Int MinMax\n        {\n            get => minMax;\n            set => minMax = value;\n        }\n\n        public int Min\n        {\n            get => minMax.x;\n            set => minMax.x = value;\n        }\n\n        public int Max\n        {\n            get => minMax.y;\n            set => minMax.y = value;\n        }\n\n        public void Add(int value)\n        {\n            Value += value;\n        }\n\n        public override int Value\n        {\n            get => isSetData ? GameData.Get(Id, initializeValue) : runtimeValue;\n            set\n            {\n                var clampedValue = IsClamped ? Mathf.Clamp(value, minMax.x, minMax.y) : value;\n                if (isSetData)\n                {\n                    GameData.Set(Id, clampedValue);\n                    if (isSaveData)\n                    {\n                        GameData.Save();\n                    }\n                }\n                else\n                {\n                    runtimeValue = clampedValue;\n                }\n#if UNITY_EDITOR\n                currentValue = clampedValue;\n#endif\n                if (isRaiseEvent)\n                {\n                    Raise(clampedValue);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c1e2751cf33a439b997c1f79b966df48\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariableListener.cs",
    "content": "﻿using VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class IntegerVariableListener : BaseVariableListener<int, IntegerVariable, IntegerEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable/IntegerVariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3184f556234f4c47b9374467cd4afcef\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Integer_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 8ec5b945a0d2f8048bbd2633196ea318\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Interface_Variable/IReference.cs",
    "content": "namespace VirtueSky.Variables\n{\n    public interface IReference\n    {\n    }\n\n    public interface IReference<TType, TVariable> : IReference\n    {\n        TType Value { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Interface_Variable/IReference.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 651c592a5818b6b49bc85bab221450ba\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Interface_Variable/IVariable.cs",
    "content": "namespace VirtueSky.Variables\n{\n    public interface IVariable<TType>\n    {\n        TType Value { get; set; }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Interface_Variable/IVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 271e3e5d558841141b076d69acb0b86b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Interface_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 639bbfa8c84a0894a87097d6726e6c80\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable/ObjectReference.cs",
    "content": "using System;\nusing Object = UnityEngine.Object;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class ObjectReference : BaseReference<Object, ObjectVariable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable/ObjectReference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 29476f09124c4a239c99d28185892add\ntimeCreated: 1651594418"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable/ObjectVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Object\", fileName = \"object_variables\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class ObjectVariable : BaseVariable<Object>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable/ObjectVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0a14f4e476834f9a917da6b6bf0b5d88\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable/ObjectVariableListener.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class ObjectVariableListener : BaseVariableListener<Object, ObjectVariable, ObjectEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable/ObjectVariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c6f3ceebb8874cd5aaa47c69b7b7c929\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Object_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 4ce15af9d90474b46b95415565f6ccee\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Rect_Variable/RectVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Rect\", fileName = \"rect_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class RectVariable : BaseVariable<Rect>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Rect_Variable/RectVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: aa90022cc8bc365459867349d32fba34\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Rect_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 54ead9d4353c75a439a658d6ad3b823b\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleReference.cs",
    "content": "﻿using System;\nusing VirtueSky.DataType;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class ShortDoubleReference : BaseReference<ShortDouble, ShortDoubleVariable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleReference.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0e49dc8d16524024cb54cf7f9c0abea8\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariable.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.DataType;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/ShortDouble\", fileName = \"short_double_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class ShortDoubleVariable : BaseVariable<ShortDouble>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 4c151fa8c0723124eb8aedcc6c272839\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariableListener.cs",
    "content": "﻿using VirtueSky.DataType;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class\n        ShortDoubleVariableListener : BaseVariableListener<ShortDouble, ShortDoubleVariable, ShortDoubleEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable/ShortDoubleVariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e1cc454b4a0e77b458061f8da8a844ca\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/ShortDouble_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 75035666cae3e504880746ddd42aa762\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/String_Variable/StringVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/String\", fileName = \"string_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class StringVariable : BaseVariable<string>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/String_Variable/StringVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ac78349e5fc985d48b9901f74f86c69c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/String_Variable/StringVariableListener.cs",
    "content": "using VirtueSky.Events;\nusing VirtueSky.Inspector;\n\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class StringVariableListener : BaseVariableListener<string, StringVariable, StringEventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/String_Variable/StringVariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 2205b9d988c5bbf41bcf05224141d0ac\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/String_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 54c0f56779550204881234dcc0693134\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Trasform_Variable/TransformReference.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class TransformReference : BaseReference<Transform, TransformVariable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Trasform_Variable/TransformReference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: 09c1018d879b4836aa50590af7928614\ntimeCreated: 1663139158"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Trasform_Variable/TransformVariable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Transform\", fileName = \"transform_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class TransformVariable : BaseVariable<Transform>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Trasform_Variable/TransformVariable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 864f507d17eb4386b9d734dc4ac56fdc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Trasform_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: fa13033c6458d384bbb6a6119e20de1d\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Reference.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class Vector2Reference : BaseReference<Vector2, Vector2Variable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Reference.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f6daaded9fe84782a274c9eb90d2dfed\ntimeCreated: 1757604090"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Variable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Vector2\", fileName = \"vector2_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class Vector2Variable : BaseVariable<Vector2>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable/Vector2Variable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: f8819a76c4614ce8b1e713e14a5b23f1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable/Vector2VariableListener.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class Vector2VariableListener : BaseVariableListener<Vector2, Vector2Variable, Vector2EventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable/Vector2VariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0b20b9568db145829e3de8df138a96eb\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector2_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 1f265618642f4328b6805b4f83450730\ntimeCreated: 1757603938"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Reference.cs",
    "content": "using System;\nusing UnityEngine;\n\nnamespace VirtueSky.Variables\n{\n    [Serializable]\n    public class Vector3Reference : BaseReference<Vector3, Vector3Variable>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Reference.cs.meta",
    "content": "﻿fileFormatVersion: 2\nguid: c8538927a6f440d09b3d9bd721c98d03\ntimeCreated: 1659591686"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Variable.cs",
    "content": "using UnityEngine;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [CreateAssetMenu(menuName = \"Sunflower/Scriptable/Variables/Vector3\", fileName = \"vector3_variable\")]\n    [EditorIcon(\"scriptable_variable\")]\n    public class Vector3Variable : BaseVariable<Vector3>\n    {\n        public Vector2 ToVector2()\n        {\n            return new Vector2(Value.x, Value.y);\n        }\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable/Vector3Variable.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7f0af1c6a8c08dd488a31bebb5f99dd7\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 8f06818ab5c1c06439abc547979c8edd, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable/Vector3VariableListener.cs",
    "content": "﻿using UnityEngine;\nusing VirtueSky.Events;\nusing VirtueSky.Inspector;\n\nnamespace VirtueSky.Variables\n{\n    [EditorIcon(\"scriptable_event_listener\")]\n    public class Vector3VariableListener : BaseVariableListener<Vector3, Vector3Variable, Vector3EventResponse>\n    {\n    }\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable/Vector3VariableListener.cs.meta",
    "content": "fileFormatVersion: 2\nguid: af20733a69844bfcac05756bcbafe724\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {fileID: 2800000, guid: 23cedf6c21faf0b4eb783f1fb5d4679a, type: 3}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/Vector3_Variable.meta",
    "content": "fileFormatVersion: 2\nguid: 99bc37103839c5b43bce252133cb3c55\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime/virtuesky.sunflower.variable.asmdef",
    "content": "{\n  \"name\": \"Virtuesky.Sunflower.Variable\",\n  \"rootNamespace\": \"\",\n  \"references\": [\n    \"GUID:bd40169efe8642149b1d2b72ba4903ce\",\n    \"GUID:32dbaa332e571bf429b7de517f75f074\",\n    \"GUID:acb3cac55c622ec459c8caadf707623a\",\n    \"GUID:540154dd0c5ed9a4dbbe695c402232fb\",\n    \"GUID:324caed91501a9c47a04ebfd87b68794\",\n    \"GUID:c282fd4f3fc2c7540914e85842a013c7\"\n  ],\n  \"includePlatforms\": [],\n  \"excludePlatforms\": [],\n  \"allowUnsafeCode\": false,\n  \"overrideReferences\": false,\n  \"precompiledReferences\": [],\n  \"autoReferenced\": true,\n  \"defineConstraints\": [],\n  \"versionDefines\": [],\n  \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Variables/Runtime/virtuesky.sunflower.variable.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 35d694408290717499b3838802212c7f\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables/Runtime.meta",
    "content": "fileFormatVersion: 2\nguid: cbd685ee2f1327248b7fea9c1587ed6e\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Variables.meta",
    "content": "fileFormatVersion: 2\nguid: 220c229567bfa014885a022face64260\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS/Vibration/HapticFeedback.mm",
    "content": "#import <UIKit/UIKit.h>\n\nextern \"C\" {\n\nvoid _impactOccurred(const char *style)\n{\n\n    UIImpactFeedbackStyle feedbackStyle;\n    if (strcmp(style, \"Heavy\") == 0)\n        feedbackStyle = UIImpactFeedbackStyleHeavy;\n    else if (strcmp(style, \"Medium\") == 0)\n        feedbackStyle = UIImpactFeedbackStyleMedium;\n    else if (strcmp(style, \"Light\") == 0)\n        feedbackStyle = UIImpactFeedbackStyleLight;\n    else if (strcmp(style, \"Rigid\") == 0)\n        if (@available(iOS 13.0, *)) {\n            feedbackStyle = UIImpactFeedbackStyleRigid;\n        } else {\n            return;\n        }\n    else if (strcmp(style, \"Soft\") == 0)\n        if (@available(iOS 13.0, *)) {\n            feedbackStyle = UIImpactFeedbackStyleSoft;\n        } else {\n            return;\n        }\n    else\n        return;\n\n    UIImpactFeedbackGenerator *generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:feedbackStyle];\n\n    [generator prepare];\n\n    [generator impactOccurred];\n}\n\nvoid _notificationOccurred(const char *style)\n{\n    UINotificationFeedbackType feedbackStyle;\n    if (strcmp(style, \"Error\") == 0)\n        feedbackStyle = UINotificationFeedbackTypeError;\n    else if (strcmp(style, \"Success\") == 0)\n        feedbackStyle = UINotificationFeedbackTypeSuccess;\n    else if (strcmp(style, \"Warning\") == 0)\n        feedbackStyle = UINotificationFeedbackTypeWarning;\n    else\n        return;\n\n    UINotificationFeedbackGenerator *generator = [[UINotificationFeedbackGenerator alloc] init];\n\n    [generator prepare];\n\n    [generator notificationOccurred:feedbackStyle];\n}\n\nvoid _selectionChanged()\n{\n    UISelectionFeedbackGenerator *generator = [[UISelectionFeedbackGenerator alloc] init];\n\n    [generator prepare];\n\n    [generator selectionChanged];\n}\n}\n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS/Vibration/HapticFeedback.mm.meta",
    "content": "fileFormatVersion: 2\nguid: 077b20d7b7a7dc14aafdb8363888b849\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: 0\n      settings: {}\n  - first:\n      Editor: Editor\n    second:\n      enabled: 0\n      settings:\n        DefaultValueInitialized: true\n  - first:\n      iPhone: iOS\n    second:\n      enabled: 1\n      settings: {}\n  - first:\n      tvOS: tvOS\n    second:\n      enabled: 1\n      settings: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.h",
    "content": "//\n//  Vibration.h\n//  https://videogamecreation.fr\n//\n//  Created by Benoît Freslon on 23/03/2017.\n//  Copyright © 2018 Benoît Freslon. All rights reserved.\n//\n#import <Foundation/Foundation.h>\n\n@interface Vibration : NSObject\n\n//////////////////////////////////////////\n\n#pragma mark - Vibrate\n\n+ (BOOL)    hasVibrator;\n+ (void)    vibrate;\n+ (void)    vibratePeek;\n+ (void)    vibratePop;\n+ (void)    vibrateNope;\n\n//////////////////////////////////////////\n\n\n@end\n\n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.h.meta",
    "content": "fileFormatVersion: 2\nguid: 83a187def68af42c29e1a38e747ea79a\nPluginImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  iconMap: {}\n  executionOrder: {}\n  isPreloaded: 0\n  isOverridable: 0\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": "VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.mm",
    "content": "//\n//  Vibration.mm\n//  https://videogamecreation.fr\n//\n//  Created by Benoît Freslon on 23/03/2017.\n//  Copyright © 2018 Benoît Freslon. All rights reserved.\n//\n#import <Foundation/Foundation.h>\n#import <AudioToolbox/AudioToolbox.h>\n#import <UIKit/UIKit.h>\n\n#import \"Vibration.h\"\n\n#define USING_IPAD UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad\n\n@interface Vibration ()\n\n@end\n\n@implementation Vibration\n\n\n\n//////////////////////////////////////////\n\n#pragma mark - Vibrate\n\n+ (BOOL)    hasVibrator {\n    return !(USING_IPAD);\n}\n+ (void)    vibrate {\n    AudioServicesPlaySystemSoundWithCompletion(1352, NULL);\n}\n+ (void)    vibratePeek {\n    AudioServicesPlaySystemSoundWithCompletion(1519, NULL); // Actuate `Peek` feedback (weak boom)\n}\n+ (void)    vibratePop {\n    AudioServicesPlaySystemSoundWithCompletion(1520, NULL); // Actuate `Pop` feedback (strong boom)\n}\n+ (void)    vibrateNope {\n    AudioServicesPlaySystemSoundWithCompletion(1521, NULL); // Actuate `Nope` feedback (series of three weak booms)\n}\n\n@end\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n#pragma mark - \"C\"\n\nextern \"C\" {\n    \n    //////////////////////////////////////////\n    // Vibrate\n    \n    bool    _HasVibrator () {\n        return [Vibration hasVibrator];\n    }\n \n    void    _Vibrate () {\n        [Vibration vibrate];\n    }\n    \n    void    _VibratePeek () {\n        [Vibration vibratePeek];\n    }\n    void    _VibratePop () {\n        [Vibration vibratePop];\n    }\n    void    _VibrateNope () {\n        [Vibration vibrateNope];\n    }\n    \n}\n\n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS/Vibration/Vibration.mm.meta",
    "content": "fileFormatVersion: 2\nguid: c31160a40d8f84d4395a22df26febd41\nPluginImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  iconMap: {}\n  executionOrder: {}\n  isPreloaded: 0\n  isOverridable: 0\n  platformData:\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  - first:\n      iPhone: iOS\n    second:\n      enabled: 1\n      settings: {}\n  - first:\n      tvOS: tvOS\n    second:\n      enabled: 1\n      settings: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS/Vibration.meta",
    "content": "fileFormatVersion: 2\nguid: 3ee19d5b94e8d485d92b70732e586af5\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins/iOS.meta",
    "content": "fileFormatVersion: 2\nguid: a8f7741f0c8fb4b3ebe08d51501d38aa\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/Plugins.meta",
    "content": "fileFormatVersion: 2\nguid: 8a18a006579744750bc5f62a817c99ae\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/README.md",
    "content": "# Vibration\n\nNative **free** plugin for Unity for iOS and Android.\nUse custom vibrations on mobile.\n# Use\n\n## Initialization\n\nInitialize the plugin with this line before using vibrations:\n\n`Vibration.Init();`\n\n## Vibrations\n\n### iOS and Android\n\n#### Default vibration\n\nUse `Vibration.Vibrate();` for a classic default ~400ms vibration\n\n#### Pop vibration\n\nPop vibration: weak boom (For iOS: only available with the haptic engine. iPhone 6s minimum or Android)\n\n`Vibration.VibratePop();`\n\n#### Peek Vibration\n\nPeek vibration: strong boom (For iOS: only available on iOS with the haptic engine. iPhone 6s minimum or Android)\n\n`Vibration.VibratePeek();`\n\n#### Nope Vibration\n\nNope vibration: series of three weak booms (For iOS: only available with the haptic engine. iPhone 6s minimum or Android)\n\n`Vibration.VibrateNope();`\n\n---\n## Android Only\n\n#### Custom duration in milliseconds\n\n`Vibration.Vibrate(500);` \n\n#### Pattern\n\n```\nlong [] pattern = { 0, 1000, 1000, 1000, 1000 };\nVibration.Vibrate ( pattern, -1 );\n```\n\n#### Cancel\n\n`Vibration.Cancel();`\n\n---\n## IOS only\nvibration using haptic engine\n\n`Vibration.VibrateIOS(ImpactFeedbackStyle.Light);`\n\n`Vibration.VibrateIOS(ImpactFeedbackStyle.Medium);`\n\n`Vibration.VibrateIOS(ImpactFeedbackStyle.Heavy);`\n\n`Vibration.VibrateIOS(ImpactFeedbackStyle.Rigid);`\n\n`Vibration.VibrateIOS(ImpactFeedbackStyle.Soft);`\n\n`Vibration.VibrateIOS(NotificationFeedbackStyle.Error);`\n\n`Vibration.VibrateIOS(NotificationFeedbackStyle.Success);`\n\n`Vibration.VibrateIOS(NotificationFeedbackStyle.Warning);`\n\n`Vibration.VibrateIOS_SelectionChanged();`"
  },
  {
    "path": "VirtueSky/Vibration/README.md.meta",
    "content": "fileFormatVersion: 2\nguid: 2af140d82dd314cbcaf375375751fea9\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/Vibration.cs",
    "content": "﻿////////////////////////////////////////////////////////////////////////////////\n//\n// @author Benoît Freslon @benoitfreslon\n// https://github.com/BenoitFreslon/Vibration\n// https://benoitfreslon.com\n//\n////////////////////////////////////////////////////////////////////////////////\n\nusing System.Runtime.InteropServices.ComTypes;\nusing UnityEngine;\nusing VirtueSky.DataStorage;\n\n#if UNITY_IOS\nusing System.Collections;\nusing System.Runtime.InteropServices;\n#endif\n\nnamespace VirtueSky.Vibration\n{\n    public static class Vibration\n    {\n#if UNITY_IOS\n    [DllImport ( \"__Internal\" )]\n    private static extern bool _HasVibrator ();\n\n    [DllImport ( \"__Internal\" )]\n    private static extern void _Vibrate ();\n\n    [DllImport ( \"__Internal\" )]\n    private static extern void _VibratePop ();\n\n    [DllImport ( \"__Internal\" )]\n    private static extern void _VibratePeek ();\n\n    [DllImport ( \"__Internal\" )]\n    private static extern void _VibrateNope ();\n\n    [DllImport(\"__Internal\")]\n    private static extern void _impactOccurred(string style);\n\n    [DllImport(\"__Internal\")]\n    private static extern void _notificationOccurred(string style);\n\n    [DllImport(\"__Internal\")]\n    private static extern void _selectionChanged();\n#endif\n\n#if UNITY_ANDROID\n        public static AndroidJavaClass unityPlayer;\n        public static AndroidJavaObject currentActivity;\n        public static AndroidJavaObject vibrator;\n        public static AndroidJavaObject context;\n\n        public static AndroidJavaClass vibrationEffect;\n\n\n#endif\n        private static bool initialized = false;\n\n        public static bool EnableVibration\n        {\n            get => GameData.Get(\"ENABLE_VIBRATION\", true);\n            set => GameData.Set(\"ENABLE_VIBRATION\", value);\n        }\n\n        public static void Init()\n        {\n            if (initialized) return;\n\n#if UNITY_ANDROID\n\n            if (Application.isMobilePlatform)\n            {\n                unityPlayer = new AndroidJavaClass(\"com.unity3d.player.UnityPlayer\");\n                currentActivity = unityPlayer.GetStatic<AndroidJavaObject>(\"currentActivity\");\n                vibrator = currentActivity.Call<AndroidJavaObject>(\"getSystemService\", \"vibrator\");\n                context = currentActivity.Call<AndroidJavaObject>(\"getApplicationContext\");\n\n                if (AndroidVersion >= 26)\n                {\n                    vibrationEffect = new AndroidJavaClass(\"android.os.VibrationEffect\");\n                }\n            }\n#endif\n\n            initialized = true;\n        }\n\n\n        public static void VibrateIOS(ImpactFeedbackStyle style)\n        {\n            if (Application.isMobilePlatform && EnableVibration) \n            {\n#if UNITY_IOS\n                _impactOccurred(style.ToString());\n#endif\n            }\n        }\n\n        public static void VibrateIOS(NotificationFeedbackStyle style)\n        {\n            if (Application.isMobilePlatform && EnableVibration) \n            {\n#if UNITY_IOS\n                _notificationOccurred(style.ToString());\n#endif\n            }\n        }\n\n        public static void VibrateIOS_SelectionChanged()\n        {\n            if (Application.isMobilePlatform && EnableVibration) \n            {\n#if UNITY_IOS\n                _selectionChanged();\n#endif\n            }\n        }\n\n\n        ///<summary>\n        /// Tiny pop vibration\n        ///</summary>\n        public static void VibratePop()\n        {\n            if (Application.isMobilePlatform && EnableVibration)\n            {\n#if UNITY_IOS\n                _VibratePop ();\n#elif UNITY_ANDROID\n                VibrateAndroid(50);\n#endif\n            }\n        }\n\n        ///<summary>\n        /// Small peek vibration\n        ///</summary>\n        public static void VibratePeek()\n        {\n            if (Application.isMobilePlatform && EnableVibration)\n            {\n#if UNITY_IOS\n                _VibratePeek ();\n#elif UNITY_ANDROID\n                VibrateAndroid(100);\n#endif\n            }\n        }\n\n        ///<summary>\n        /// 3 small vibrations\n        ///</summary>\n        public static void VibrateNope()\n        {\n            if (Application.isMobilePlatform && EnableVibration)\n            {\n#if UNITY_IOS\n                _VibrateNope ();\n#elif UNITY_ANDROID\n                long[] pattern = { 0, 50, 50, 50 };\n                VibrateAndroid(pattern, -1);\n#endif\n            }\n        }\n\n\n#if UNITY_ANDROID\n        ///<summary>\n        /// Only on Android\n        /// https://developer.android.com/reference/android/os/Vibrator.html#vibrate(long)\n        ///</summary>\n        public static void VibrateAndroid(long milliseconds)\n        {\n            if (Application.isMobilePlatform && EnableVibration)\n            {\n                if (AndroidVersion >= 26)\n                {\n                    AndroidJavaObject createOneShot =\n                        vibrationEffect.CallStatic<AndroidJavaObject>(\"createOneShot\", milliseconds, -1);\n                    vibrator.Call(\"vibrate\", createOneShot);\n                }\n                else\n                {\n                    vibrator.Call(\"vibrate\", milliseconds);\n                }\n            }\n        }\n\n        ///<summary>\n        /// Only on Android\n        /// https://proandroiddev.com/using-vibrate-in-android-b0e3ef5d5e07\n        ///</summary>\n        public static void VibrateAndroid(long[] pattern, int repeat)\n        {\n            if (Application.isMobilePlatform && EnableVibration)\n            {\n                if (AndroidVersion >= 26)\n                {\n                    long[] amplitudes;\n                    AndroidJavaObject createWaveform =\n                        vibrationEffect.CallStatic<AndroidJavaObject>(\"createWaveform\", pattern, repeat);\n                    vibrator.Call(\"vibrate\", createWaveform);\n                }\n                else\n                {\n                    vibrator.Call(\"vibrate\", pattern, repeat);\n                }\n            }\n        }\n#endif\n\n        ///<summary>\n        ///Only on Android\n        ///</summary>\n        public static void CancelAndroid()\n        {\n            if (Application.isMobilePlatform)\n            {\n#if UNITY_ANDROID\n                vibrator.Call(\"cancel\");\n#endif\n            }\n        }\n\n        public static bool HasVibrator()\n        {\n            if (Application.isMobilePlatform)\n            {\n#if UNITY_ANDROID\n\n                AndroidJavaClass contextClass = new AndroidJavaClass(\"android.content.Context\");\n                string Context_VIBRATOR_SERVICE = contextClass.GetStatic<string>(\"VIBRATOR_SERVICE\");\n                AndroidJavaObject systemService =\n                    context.Call<AndroidJavaObject>(\"getSystemService\", Context_VIBRATOR_SERVICE);\n                if (systemService.Call<bool>(\"hasVibrator\"))\n                {\n                    return true;\n                }\n                else\n                {\n                    return false;\n                }\n\n#elif UNITY_IOS\n        return _HasVibrator ();\n#else\n        return false;\n#endif\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n\n        public static void Vibrate()\n        {\n#if UNITY_ANDROID || UNITY_IOS\n\n            if (Application.isMobilePlatform && EnableVibration)\n            {\n                Handheld.Vibrate();\n            }\n\n#endif\n        }\n\n        public static int AndroidVersion\n        {\n            get\n            {\n                int iVersionNumber = 0;\n                if (Application.platform == RuntimePlatform.Android)\n                {\n                    string androidVersion = SystemInfo.operatingSystem;\n                    int sdkPos = androidVersion.IndexOf(\"API-\");\n                    iVersionNumber = int.Parse(androidVersion.Substring(sdkPos + 4, 2).ToString());\n                }\n\n                return iVersionNumber;\n            }\n        }\n    }\n\n    public enum ImpactFeedbackStyle\n    {\n        Heavy,\n        Medium,\n        Light,\n        Rigid,\n        Soft\n    }\n\n    public enum NotificationFeedbackStyle\n    {\n        Error,\n        Success,\n        Warning\n    }\n}"
  },
  {
    "path": "VirtueSky/Vibration/Vibration.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9a1817bb553014d4c9a665d4fa202202\ntimeCreated: 1474899097\nlicenseType: Pro\nMonoImporter:\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration/virtuesky.sunflower.vibration.asmdef",
    "content": "{\n    \"name\": \"Virtuesky.Sunflower.Vibration\",\n    \"rootNamespace\": \"\",\n    \"references\": [\n        \"GUID:32dbaa332e571bf429b7de517f75f074\"\n    ],\n    \"includePlatforms\": [],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "VirtueSky/Vibration/virtuesky.sunflower.vibration.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: bd0c6a52234db0b4db0b3a5ab149f81c\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky/Vibration.meta",
    "content": "fileFormatVersion: 2\nguid: 416bc8852a98c49bbaa3260119445847\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "VirtueSky.meta",
    "content": "fileFormatVersion: 2\nguid: 284b2e8243e944a4782887d76e984d71\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"com.virtuesky.sunflower\",\n  \"displayName\": \"Sunflower\",\n  \"description\": \"Core ScriptableObject Architecture for building Unity games\",\n  \"version\": \"3.5.5-preview\",\n  \"unity\": \"2022.3\",\n  \"category\": \"virtuesky\",\n  \"author\": {\n    \"name\": \"virtuesky\",\n    \"email\": \"virtuesky.0520@gmail.com\",\n    \"url\": \"https://github.com/VirtueSky\"\n  },\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"ScriptableObjectArchitecture\",\n    \"ScriptableObject\",\n    \"Architecture\",\n    \"Unity\"\n  ],\n  \"dependencies\": {\n    \"com.unity.serialization\": \"3.1.1\",\n    \"com.unity.collections\": \"2.1.4\",\n    \"com.unity.textmeshpro\": \"3.0.8\",\n    \"com.unity.addressables\": \"1.21.21\",\n    \"com.cysharp.unitask\": \"https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.5.10\",\n    \"com.kyrylokuzyk.primetween\": \"1.3.8\"\n  }\n}"
  },
  {
    "path": "package.json.meta",
    "content": "fileFormatVersion: 2\nguid: 124b2d6d5f51c4f1f970cf0138354eb3\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  }
]